parse-community/parse-server
Parse Server for Node.js / Express
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.
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.
- 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
- 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]
- 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]
- 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]
- 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]
- 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]
- 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.
parse/node packagePlain 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
src/RestQuery.jsObject 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
src/RestWrite.jsObject 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
src/Auth.jsObject 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
src/Config.jsObject 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
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
Hidden Assumptions
Things this code relies on but never validates. These are the things that cause silent failures when the system changes.
HTTP requests will always contain a Host header that is valid for constructing URLs - getMountForRequest() concatenates req.protocol + '://' + req.get('host') without validating that host header exists or is properly formatted
If this fails: 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
src/middlewares.js:handleParseHeaders
AppCache.get(applicationId) will return an object with known structure if it returns truthy - the forEach loop assumes all cache values are either 'databaseController' or simple config properties that can be directly assigned
If this fails: 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
src/Config.js:Config.get
The bodyparser middleware has already run before handleParseHeaders executes - comment states 'The bodyparser should run before this middleware' but there's no enforcement
If this fails: 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
src/middlewares.js:handleParseHeaders
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
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
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
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
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
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
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
System Behavior
How the system operates at runtime — where data accumulates, what loops, what waits, and what controls what.
Data Pools
Caches Parse app configurations by applicationId to avoid reloading settings on every request
Caches database schemas to avoid repeated schema fetches during query planning and validation
Caches user role memberships per request to avoid repeated role queries during ACL checks
Stores active WebSocket subscriptions with their query filters to match against data changes
Feedback Loops
- Session Refresh (auto-scale, reinforcing) — Trigger: Session token validation. Action: Updates session expiration if more than half the session length has passed. Exit: Session remains valid or user must re-authenticate.
- LiveQuery Updates (polling, reinforcing) — Trigger: Database write operations. Action: Checks all active subscriptions against changed objects and sends updates to matching WebSocket clients. Exit: All matching subscriptions notified.
- Rate Limiting (backpressure, balancing) — Trigger: Too many requests from IP/user. Action: Returns 429 status and delays further requests. Exit: Rate limit window expires.
Delays
- Database Connection Pool (async-processing, ~varies) — Requests wait for available connection from pool before executing queries
- File Upload Processing (async-processing, ~varies) — Large file uploads are processed asynchronously while client waits for completion
- Push Notification Queue (queue-drain, ~configurable) — Push notifications are queued and sent in batches to avoid overwhelming external services
Control Points
- masterKey (feature-flag) — Controls: Bypasses all ACL and CLP restrictions when provided in X-Parse-Master-Key header
- enableSingleSchemaCache (architecture-switch) — Controls: Whether to cache database schemas globally vs per-request to trade memory for performance
- databaseAdapter (architecture-switch) — Controls: Which database backend (MongoDB or PostgreSQL) to use for data storage
- rateLimit (rate-limit) — Controls: Maximum requests per window per IP address to prevent abuse
- enableSanitizedErrorResponse (feature-flag) — Controls: Whether to return detailed error messages or sanitized ones to prevent information leakage
Technology Stack
HTTP server framework that handles routing, middleware, and request/response processing
Primary database backend with aggregation pipeline support for complex Parse queries
Alternative database backend using JSON columns for flexible schema support
Alternative query interface using Apollo Server that maps to same controllers as REST API
Real-time communication for LiveQuery subscriptions using ws library
Password hashing for secure user authentication
JWT token generation and validation for session management
Optional caching layer and rate limiting store
Key Components
- ParseServer (orchestrator) — Main server class that initializes all controllers, sets up Express app with middleware and routers, and manages server lifecycle
src/ParseServer.js - DatabaseController (orchestrator) — Central hub for all database operations - executes queries, manages schemas, handles indexes, and coordinates with storage adapters
src/Controllers/DatabaseController.js - handleParseHeaders (validator) — Express middleware that validates Parse API headers (app ID, keys, session tokens), loads app config, and creates Auth object for request
src/middlewares.js - PromiseRouter (adapter) — Router base class that adapts promise-based handlers to Express routing, handling async operations and standardizing response formats
src/PromiseRouter.js - RestQuery (processor) — Processes GET requests and find operations - parses query parameters, applies ACL filtering, executes database queries, and formats results
src/RestQuery.js - RestWrite (processor) — Processes POST/PUT/DELETE requests - validates data against schemas, runs beforeSave triggers, executes writes, and runs afterSave triggers
src/RestWrite.js - MongoStorageAdapter (adapter) — MongoDB implementation of database operations - translates Parse queries to MongoDB aggregation pipelines and manages collections
src/Adapters/Storage/Mongo/MongoStorageAdapter.js - authDataManager (registry) — Manages third-party authentication providers (Facebook, Google, Twitter) - validates auth tokens and retrieves user data
src/Adapters/Auth/index.js - triggers (executor) — Manages and executes cloud code triggers (beforeSave, afterSave, beforeDelete) and cloud functions at appropriate points in request lifecycle
src/triggers.js - LiveQueryController (orchestrator) — Manages real-time subscriptions - tracks client queries, broadcasts data changes via WebSocket, and handles subscription lifecycle
src/Controllers/LiveQueryController.js
Explore the interactive analysis
See the full architecture map, data flow, and code patterns visualization.
Analyze on CodeSeaRelated 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 Karolina Sarna.