Reference
Configuration
Settings, schema generation, indexes and the optional role cache.
configureKit
Optional. Every default reproduces what the library did before these became settings, so a project that never calls it is unaffected. Values resolve when they are used, not at import, so calling it after dotenv still works.
configureKit({
mountPath: '/api', // default: process.env.mountPath, then '/parse'
masterKey: process.env.MASTER_KEY, // default: process.env.masterKey
adminRole: 'Owner', // default: 'SuperAdmin'
allowAuthRoutes: false, // default: false
excludedPointerClasses: ['Attachment'], // default: ['IMG', 'File']
});
restrictRoutes compares against it to let privileged callers past the
route restrictions. With nothing configured there is nothing to compare against, so a
caller presenting a perfectly valid master key is refused — and nothing says why.
allowAuthRoutes
restrictRoutes closes Parse's generic REST API so clients go through the
cloud functions you declared. Its auth endpoints are closed along with everything else,
and the documented approach is to expose the ones you want yourself:
import {
configureKit, Route, CloudFunction, createSchemaConfig, applyAllIndexes,
applyMongoValidators, configureRoleCache, invalidateRoles,
} from 'parse-server-kit';
@Route(User)
class UserFunctions {
// POST /api/users/logIn - your endpoint, so you can rate limit it,
// lock accounts out, and log attempts.
@CloudFunction({ methods: ['POST'] })
static async logIn(req: Parse.Cloud.FunctionRequest) { ... }
}
That is the right default for a REST client you control, and the wrong one if your
client is a Parse SDK. Parse.User.logIn() in the browser, on iOS or on
Android calls /login directly and cannot be pointed at a cloud function, so
those apps need this on:
configureKit({ allowAuthRoutes: true });
It opens exactly these, and only with the method that makes sense:
| Route | Method | What it is |
|---|---|---|
/login | GET, POST | Log in |
/logout | POST | End the session |
/users | POST only | Sign up |
/users/me | GET | The current user |
/sessions/me | GET | The current session |
/requestPasswordReset | POST | Send a reset email |
/verificationEmailRequest | POST | Resend verification |
POST /users signs somebody up; GET /users queries the whole
user table. The method is part of the match, so turning this on never opens the second
one. PUT /users/<id> stays blocked too — expose a profile-update cloud
function instead.
Leaving it off is not a dead end: the 403 names the setting and suggests the cloud function alternative, so whichever route you meant to take is discoverable from the response.
createSchemaConfig
const schema = createSchemaConfig({ adminRole: 'Owner' });
// pass as the `schema` option to ParseServer
| Option | Default | Effect |
|---|---|---|
adminRole | from configureKit | Role permitted to manage _Role |
lockSchemas | false | Reject new classes and fields |
strict | true | Create missing classes and fields at boot |
recreateModifiedFields | false | Destructive — drops and recreates a field whose type changed |
deleteExtraFields | false | Destructive — removes fields not in the schema |
keepUnknownIndexes | true | Keeps indexes the schema does not describe |
keepUnknownIndexes defaults to true because applyAllIndexes creates indexes by talking to MongoDB directly, so parse-server's schema sync has never heard of them. Its own default removes indexes it cannot account for — taking your uniqueness constraints with it. Requires parse-server 8.3+.
Indexes
await applyAllIndexes(parseServer); // after listen()
await applyMongoValidators(parseServer);
| Declared as | Creates |
|---|---|
@ParseField({unique: true}) | Unique index — drops a conflicting non-unique one first |
@ParseField({index: true | 1 | -1}) | B-tree, ascending or descending |
@ParseField({geo: true}) | 2dsphere |
@ParseField({ttlSeconds: N}) | TTL |
@ParseClass({compoundIndexes}) | Compound, optionally unique, sparse, partial or text |
An index that already exists is reported, not treated as an error. If the adapter cannot be reached, the equivalent db.collection.createIndex(…) commands are printed so you can run them yourself. MongoDB permits only one text index per collection.
Role cache
Off by default. requireRoles and getUserRoles() each cost a database round-trip. Role membership rarely changes, so it caches well — but a revoked role keeps working until the entry expires, and that trade belongs to whoever runs the deployment.
configureRoleCache({ ttlMs: 30_000 }); // global
invalidateRoles(userId); // on grant or revoke
configureRoleCache(false); // off, and cleared
@CloudFunction({ requireRoles: ['Admin'], roleCacheMs: 0 }) // never cached
Wire invalidateRoles into your own grant and revoke paths and the TTL only ever covers changes made outside your code. Entries expire when read and the map is bounded by maxUsers; there is no timer.