Guide

Getting started

Three commands to a running API with OpenAPI docs, a seeded user, and a MongoDB configured so transactions actually work.

Requirements

Node≥ 20.19
MongoDB≥ 7.0.16 for parse-server 9. A replica set is required for transactions
TypeScriptAny version, with experimentalDecorators: true

Create a project

npx parse-server-kit new my-api
cd my-api
npm run db:up
npm run dev

The generated project prints a ready-to-paste curl on startup, including a session token for a seeded demo user, so your first request works immediately rather than answering 400.

Why Docker rather than a local install A default MongoDB install runs as a standalone, and standalones refuse transactions — so @Transactional and @ParseVersionField would fail against one. The generated docker-compose.yml configures a single-node replica set to avoid that. Not using Docker? Put a MongoDB Atlas connection string in DATABASE_URI and skip the compose step; Atlas is already a replica set.

What was generated

my-api/
├── docker-compose.yml     # MongoDB as a replica set
├── tsconfig.json          # decorator flags already set
├── .env
└── src/
    ├── app.ts             # boot order — the sequence matters
    ├── roles.ts           # your roles, declared once
    ├── seed.ts            # roles, first admin, sample rows
    ├── models/Note.ts     # @ParseClass + @ParseField + a trigger
    ├── functions/note.ts  # @Route + five endpoints
    └── server/            # plumbing: banner, dashboard mount

Your API is at /api/notes/* and its documentation at /api-docs.

Your first request

Both of these are real exchanges against a freshly generated project — the responses below are what the server actually returned.

Create — needs the session token printed at startup
curl -X POST "http://localhost:1337/api/notes/createNote" \
  -H "X-Parse-Application-Id: my-api" \
  -H "X-Parse-Session-Token: <token>" \
  -H "Content-Type: text/plain" \
  -d '{"title":"Quarterly report","body":"Revenue up.","status":"published"}'
Three fields in, eight out
{ "title": "Quarterly report",
  "body": "Revenue up.",
  "status": "published",
  "slug": "quarterly-report",          // derived
  "views": 0,                          // defaulted
  "objectId": "21R47fDVEB",
  "createdAt": "2026-08-24T09:17:13.202Z",
  "updatedAt": "2026-08-24T09:17:13.202Z" }

slug was derived and views defaulted by the model's @BeforeSave trigger, which also validated the whole object. That happens on every save path, not only this endpoint.

List — no auth needed
curl "http://localhost:1337/api/notes/listNotes?limit=2&status=published" \
  -H "X-Parse-Application-Id: my-api"

Query-string values arrive as stringsvalidateEntityRoutes merges them into the body. Declare them {type: String} and convert: Number(req.params.limit).

Only rows this caller may read
{ "results": [
    { "objectId": "MJq00knE1O", "title": "Welcome",
      "slug": "welcome", "status": "published", "views": 0,
      "ACL": { "*": { "read": true },
               "role:Editor": { "read": true, "write": true } } }
  ], "count": 1 }

The seeded draft note exists too and is simply invisible here — no where clause did that, the row's ACL did. See Permissions & ACL.

Parse Dashboard

Parse has an official admin console — browse and edit every class, run queries, inspect users and roles, send push. It is not installed by default, and getting it is one command:

npm install parse-dashboard
npm run dev

Restart and it is at http://localhost:1337/dashboard. The generated app.ts already detects it, so there is nothing to wire, and the startup banner tells you whether it came up.

It holds the master key Which is what lets it read and write every class regardless of CLP or ACL — so set DASHBOARD_USER and DASHBOARD_PASS in .env before it goes anywhere. Unset in production it refuses to mount at all. The full page on the dashboard covers read-only operators, HTTPS, and how to expose it safely.

Adding your own entity

psk g resource Product

Writes src/models/Product.ts and src/functions/product.ts with the edit points marked, and changes nothing else — there is no module to register into, because importFiles discovers both at boot.

TypeScript setup

If you are adding this to an existing project rather than generating one, one compiler flag is mandatory:

{
  "compilerOptions": {
    "experimentalDecorators": true
  }
}

This library uses legacy decorators. TypeScript 5 defaults to the standard (TC39) ones, which are a different feature — without the flag every decorator misbehaves. emitDecoratorMetadata is not needed.

Declaring fields Write model fields as declare name: string rather than name!: string. @ParseField installs an accessor on the prototype, and a real class field would shadow it. @ParseClass repairs that automatically, but declare states what is actually true: the storage belongs to Parse, not the instance. The full explanation.

Where Parse's own docs take over

This site covers what this library adds. For Parse Server itself — query operators, ACL semantics, LiveQuery, file adapters, push, authentication providers — the Parse Platform documentation remains the reference, and nothing here replaces it.