parse-community/parse-server

Parse Server for Node.js / Express

21,383 stars JavaScript 10 components

12 hidden assumptions · 7-stage pipeline · 10 components

Like any codebase, this backend api makes assumptions it never checks — most are routine. The ones worth your attention are below.

Provides Parse-compatible REST API and GraphQL endpoints for mobile/web apps with database abstraction

HTTP requests enter through Express middleware that validates Parse headers and loads app configuration. Requests are routed to specific handlers (ClassesRouter for /classes, UsersRouter for /users) which create RestQuery or RestWrite objects. These objects execute database operations through DatabaseController and storage adapters, with ACL filtering and trigger execution. Responses are formatted as JSON and returned to clients, with some operations also triggering real-time updates via LiveQuery.

Under the hood, the system uses 3 feedback loops, 4 data pools, 5 control points to manage its runtime behavior.

A 10-component backend api. 373 files analyzed. Data flows through 7 distinct pipeline stages.

Hidden Assumptions

Most of what this code assumes is routine. These 3 are the ones most likely to cause trouble here. The rest are minor; they're under "Show everything".

Worth your attention first

If a malicious client omits or corrupts the Host header, config lookup fails silently returning undefined, causing all subsequent middleware to crash with 'Cannot read properties of undefined' when accessing config properties

Worth your attention first

If AppCache contains unexpected nested objects, circular references, or functions as values, they get assigned directly to config causing type errors or memory leaks when config is used throughout the request lifecycle

Worth your attention first

If bodyparser hasn't run, req.body is undefined causing Parse operations that expect parsed JSON data to fail with cryptic errors when trying to access request.data properties

Show everything (9 more)
Temporal

IP address whitelist/blocklist configuration doesn't change during server runtime - results are cached in store.set(ip, result) with no TTL or invalidation mechanism

If this fails: If administrators update IP restrictions in a running system, previously cached IP decisions persist indefinitely, allowing blocked IPs continued access or denying newly allowed IPs until server restart

src/middlewares.js:checkIp
Contract

Parse class objects will have either a 'className' property or a 'name' property that follows the convention of being prefixed with 'Parse' - the fallback return parseClass assumes it's already a string

If this fails: If a trigger is registered with an object that has neither property, or a name that doesn't start with 'Parse', the system returns the entire object as className causing trigger lookups to fail silently

src/triggers.js:getClassName
Resource

SQL query files exist in the expected filesystem structure relative to __dirname and are readable at startup time

If this fails: If any .sql files are missing, moved, or have wrong permissions, QueryFile constructor throws immediately causing entire server startup to fail with unclear error about missing database functionality

src/Adapters/Storage/Postgres/sql/index.js:sql
Scale

IP range lists (ipRangeList) contain a reasonable number of entries that can be processed synchronously during request handling without blocking the event loop

If this fails: With thousands of IP ranges, the synchronous forEach loop and BlockList.addSubnet calls can block the event loop for hundreds of milliseconds, causing request timeouts and degraded performance for all clients

src/middlewares.js:getBlockList
Domain

className parameters follow the regex pattern _?[A-Za-z][A-Za-z_0-9]* which allows Parse system classes (prefixed with _) and user classes but excludes certain valid Unicode class names

If this fails: Applications using internationalized class names with Unicode characters (like Chinese or Arabic class names) will have their routes fail validation, making the API inaccessible for non-Latin class names

src/PromiseRouter.js:validateParameter
Environment

All adapter constructors (WinstonLoggerAdapter, GridFSBucketAdapter, etc.) can be instantiated successfully with the provided options - loadAdapter() is called without try-catch

If this fails: If any adapter fails to initialize (missing dependencies, invalid config, network issues), the entire server startup fails with an unhandled exception instead of gracefully degrading or providing clear error messages

src/Controllers/index.js:getControllers
Contract

Async config functions stored as this._${key} will resolve to simple values that can be assigned directly to this[key] without validation

If this fails: If an async config function like _publicServerURL returns null, undefined, or a malformed URL, it gets assigned directly to the config causing downstream URL construction to fail in REST operations or webhook callbacks

src/Config.js:Config.loadKeys
Ordering

Trigger type validation happens before triggers are actually registered and executed - the validation throws strings instead of Error objects

If this fails: Code that expects standard Error objects with stack traces for logging will fail to properly capture and report trigger validation failures, making debugging trigger registration issues difficult

src/triggers.js:validateClassNameForTriggers
Shape

Test code expects adapter constructors to throw strings rather than Error objects when options.throw is true - throws 'MockFilesAdapterConstructor' as a string

If this fails: Production error handling code that expects Error instances with proper stack traces will not work correctly in tests, potentially masking real error handling bugs that only surface in production

spec/dependencies/mock-files-adapter/index.js:constructor

Open the standalone hidden-assumptions report for parse-server →

How Data Flows Through the System

HTTP requests enter through Express middleware that validates Parse headers and loads app configuration. Requests are routed to specific handlers (ClassesRouter for /classes, UsersRouter for /users) which create RestQuery or RestWrite objects. These objects execute database operations through DatabaseController and storage adapters, with ACL filtering and trigger execution. Responses are formatted as JSON and returned to clients, with some operations also triggering real-time updates via LiveQuery.

  1. Parse request headers — handleParseHeaders middleware extracts X-Parse-Application-Id, authentication tokens, and other Parse-specific headers, loads Config from AppCache, and creates Auth object with user permissions
  2. Route to handler — Express routes in src/Routers/ (ClassesRouter, UsersRouter, etc.) match URL patterns and HTTP methods, validate basic request structure, and delegate to appropriate handler methods [Auth]
  3. Build operation object — For queries, RestQuery constructor parses where conditions, select fields, limit/skip from request. For writes, RestWrite constructor extracts object data and validates against existing object if updating [Auth → RestQuery]
  4. Execute triggers — For writes, beforeSave triggers run first and can modify data or abort operation. For queries, beforeFind triggers can modify query parameters or return objects directly bypassing database [RestQuery → RestQuery]
  5. Execute database operation — DatabaseController translates Parse operations to adapter-specific queries (MongoDB aggregation pipelines or PostgreSQL SQL), applies ACL filtering, and executes against storage adapter [RestQuery → ParseObject]
  6. Apply transforms and ACLs — Results are filtered by ACL permissions, sensitive fields removed based on user roles, and data transformed to Parse API format with objectId, createdAt, updatedAt fields [ParseObject → ParseObject]
  7. Send response — Final results formatted as JSON response with appropriate HTTP status codes, location headers for creates, and error messages for failures [ParseObject]

Data Models

The data structures that flow between stages — the contracts that hold the system together.

ParseObject parse/node package
Plain object with className: string, objectId: string, createdAt: Date, updatedAt: Date, ACL: object, plus arbitrary user-defined fields
Created from HTTP request JSON, validated against schema, stored in database, retrieved with ACL filtering applied
RestQuery src/RestQuery.js
Object with restWhere: object (query constraints), restOptions: object (limit, skip, include, keys), className: string, auth: Auth object
Built from HTTP query parameters and request body, executed against database with ACL filtering, results transformed for response
RestWrite src/RestWrite.js
Object with className: string, query: object, data: object (fields to update), originalData: object, auth: Auth, clientSDK: object
Constructed from POST/PUT requests, validated against schema and ACLs, triggers executed, data written to database
Auth src/Auth.js
Object with config: Config, user: Parse.User, isMaster: boolean, userRoles: array, installationId: string
Created from request headers (session token, master key), user and roles loaded from database, used throughout request for permission checks
Config src/Config.js
Object with applicationId: string, masterKey: string, databaseController: DatabaseController, plus all ParseServerOptions fields
Loaded at startup from options, cached in AppCache by applicationId, retrieved for each request to access app settings
DatabaseAdapter src/Adapters/Storage/
Interface with methods find(className, schema, query, options), create(className, schema, object), update(className, schema, query, update)
Instantiated at startup with connection details, used by DatabaseController to execute all database operations

System Behavior

How the system operates at runtime — where data accumulates, what loops, what waits, and what controls what.

Data Pools

AppCache (in-memory)
Caches Parse app configurations by applicationId to avoid reloading settings on every request
Schema Cache (in-memory)
Caches database schemas to avoid repeated schema fetches during query planning and validation
User Role Cache (in-memory)
Caches user role memberships per request to avoid repeated role queries during ACL checks
LiveQuery Subscriptions (in-memory)
Stores active WebSocket subscriptions with their query filters to match against data changes

Feedback Loops

Delays

Control Points

Technology Stack

Express (framework)
HTTP server framework that handles routing, middleware, and request/response processing
MongoDB (database)
Primary database backend with aggregation pipeline support for complex Parse queries
PostgreSQL (database)
Alternative database backend using JSON columns for flexible schema support
GraphQL (library)
Alternative query interface using Apollo Server that maps to same controllers as REST API
WebSocket (library)
Real-time communication for LiveQuery subscriptions using ws library
bcrypt (library)
Password hashing for secure user authentication
jsonwebtoken (library)
JWT token generation and validation for session management
Redis (database)
Optional caching layer and rate limiting store

Key Components

Explore the interactive analysis

See the full architecture map, data flow, and code patterns visualization.

Analyze on CodeSea

Related Backend Api Repositories

Frequently Asked Questions

What is parse-server used for?

Provides Parse-compatible REST API and GraphQL endpoints for mobile/web apps with database abstraction parse-community/parse-server is a 10-component backend api written in JavaScript. Data flows through 7 distinct pipeline stages. The codebase contains 373 files.

How is parse-server architected?

parse-server is organized into 4 architecture layers: HTTP Layer, Controller Layer, Adapter Layer, GraphQL Layer. Data flows through 7 distinct pipeline stages. This layered structure keeps concerns separated and modules independent.

How does data flow through parse-server?

Data moves through 7 stages: Parse request headers → Route to handler → Build operation object → Execute triggers → Execute database operation → .... HTTP requests enter through Express middleware that validates Parse headers and loads app configuration. Requests are routed to specific handlers (ClassesRouter for /classes, UsersRouter for /users) which create RestQuery or RestWrite objects. These objects execute database operations through DatabaseController and storage adapters, with ACL filtering and trigger execution. Responses are formatted as JSON and returned to clients, with some operations also triggering real-time updates via LiveQuery. This pipeline design reflects a complex multi-stage processing system.

What technologies does parse-server use?

The core stack includes Express (HTTP server framework that handles routing, middleware, and request/response processing), MongoDB (Primary database backend with aggregation pipeline support for complex Parse queries), PostgreSQL (Alternative database backend using JSON columns for flexible schema support), GraphQL (Alternative query interface using Apollo Server that maps to same controllers as REST API), WebSocket (Real-time communication for LiveQuery subscriptions using ws library), bcrypt (Password hashing for secure user authentication), and 2 more. A focused set of dependencies that keeps the build manageable.

What system dynamics does parse-server have?

parse-server exhibits 4 data pools (AppCache, Schema Cache), 3 feedback loops, 5 control points, 3 delays. The feedback loops handle auto-scale and polling. These runtime behaviors shape how the system responds to load, failures, and configuration changes.

What design patterns does parse-server use?

5 design patterns detected: Adapter Pattern, Middleware Pipeline, Controller Facade, Registry Pattern, Observer Pattern.

Analyzed on April 20, 2026 by CodeSea. Written by .