@beiguancyc/parse-server 9.9.0-ruixiang.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/LICENSE +176 -0
  2. package/NOTICE +10 -0
  3. package/README.md +1311 -0
  4. package/bin/parse-live-query-server +3 -0
  5. package/bin/parse-server +3 -0
  6. package/lib/AccountLockout.js +149 -0
  7. package/lib/Adapters/AdapterLoader.js +60 -0
  8. package/lib/Adapters/Analytics/AnalyticsAdapter.js +32 -0
  9. package/lib/Adapters/Auth/AuthAdapter.js +132 -0
  10. package/lib/Adapters/Auth/BaseCodeAuthAdapter.js +119 -0
  11. package/lib/Adapters/Auth/OAuth1Client.js +204 -0
  12. package/lib/Adapters/Auth/apple.js +125 -0
  13. package/lib/Adapters/Auth/facebook.js +187 -0
  14. package/lib/Adapters/Auth/gcenter.js +217 -0
  15. package/lib/Adapters/Auth/github.js +125 -0
  16. package/lib/Adapters/Auth/google.js +122 -0
  17. package/lib/Adapters/Auth/gpgames.js +125 -0
  18. package/lib/Adapters/Auth/httpsRequest.js +41 -0
  19. package/lib/Adapters/Auth/index.js +248 -0
  20. package/lib/Adapters/Auth/instagram.js +118 -0
  21. package/lib/Adapters/Auth/janraincapture.js +85 -0
  22. package/lib/Adapters/Auth/janrainengage.js +57 -0
  23. package/lib/Adapters/Auth/keycloak.js +168 -0
  24. package/lib/Adapters/Auth/ldap.js +193 -0
  25. package/lib/Adapters/Auth/line.js +125 -0
  26. package/lib/Adapters/Auth/linkedin.js +117 -0
  27. package/lib/Adapters/Auth/meetup.js +44 -0
  28. package/lib/Adapters/Auth/mfa.js +334 -0
  29. package/lib/Adapters/Auth/microsoft.js +111 -0
  30. package/lib/Adapters/Auth/oauth2.js +115 -0
  31. package/lib/Adapters/Auth/phantauth.js +53 -0
  32. package/lib/Adapters/Auth/qq.js +113 -0
  33. package/lib/Adapters/Auth/spotify.js +115 -0
  34. package/lib/Adapters/Auth/twitter.js +197 -0
  35. package/lib/Adapters/Auth/utils.js +28 -0
  36. package/lib/Adapters/Auth/vkontakte.js +55 -0
  37. package/lib/Adapters/Auth/wechat.js +110 -0
  38. package/lib/Adapters/Auth/weibo.js +141 -0
  39. package/lib/Adapters/Cache/CacheAdapter.js +40 -0
  40. package/lib/Adapters/Cache/InMemoryCache.js +61 -0
  41. package/lib/Adapters/Cache/InMemoryCacheAdapter.js +34 -0
  42. package/lib/Adapters/Cache/LRUCache.js +35 -0
  43. package/lib/Adapters/Cache/NullCacheAdapter.js +26 -0
  44. package/lib/Adapters/Cache/RedisCacheAdapter.js +109 -0
  45. package/lib/Adapters/Cache/SchemaCache.js +25 -0
  46. package/lib/Adapters/Email/MailAdapter.js +32 -0
  47. package/lib/Adapters/Files/FilesAdapter.js +129 -0
  48. package/lib/Adapters/Files/GridFSBucketAdapter.js +280 -0
  49. package/lib/Adapters/Files/GridStoreAdapter.js +5 -0
  50. package/lib/Adapters/Logger/LoggerAdapter.js +27 -0
  51. package/lib/Adapters/Logger/WinstonLogger.js +107 -0
  52. package/lib/Adapters/Logger/WinstonLoggerAdapter.js +63 -0
  53. package/lib/Adapters/MessageQueue/EventEmitterMQ.js +55 -0
  54. package/lib/Adapters/PubSub/EventEmitterPubSub.js +53 -0
  55. package/lib/Adapters/PubSub/PubSubAdapter.js +34 -0
  56. package/lib/Adapters/PubSub/RedisPubSub.js +49 -0
  57. package/lib/Adapters/Push/PushAdapter.js +40 -0
  58. package/lib/Adapters/Storage/Mongo/MongoCollection.js +212 -0
  59. package/lib/Adapters/Storage/Mongo/MongoSchemaCollection.js +334 -0
  60. package/lib/Adapters/Storage/Mongo/MongoStorageAdapter.js +1047 -0
  61. package/lib/Adapters/Storage/Mongo/MongoTransform.js +1397 -0
  62. package/lib/Adapters/Storage/Postgres/PostgresClient.js +38 -0
  63. package/lib/Adapters/Storage/Postgres/PostgresConfigParser.js +73 -0
  64. package/lib/Adapters/Storage/Postgres/PostgresStorageAdapter.js +2409 -0
  65. package/lib/Adapters/Storage/Postgres/sql/array/add-unique.sql +11 -0
  66. package/lib/Adapters/Storage/Postgres/sql/array/add.sql +11 -0
  67. package/lib/Adapters/Storage/Postgres/sql/array/contains-all-regex.sql +14 -0
  68. package/lib/Adapters/Storage/Postgres/sql/array/contains-all.sql +14 -0
  69. package/lib/Adapters/Storage/Postgres/sql/array/contains.sql +11 -0
  70. package/lib/Adapters/Storage/Postgres/sql/array/remove.sql +11 -0
  71. package/lib/Adapters/Storage/Postgres/sql/index.js +32 -0
  72. package/lib/Adapters/Storage/Postgres/sql/misc/json-object-set-keys.sql +19 -0
  73. package/lib/Adapters/Storage/StorageAdapter.js +2 -0
  74. package/lib/Adapters/WebSocketServer/WSAdapter.js +35 -0
  75. package/lib/Adapters/WebSocketServer/WSSAdapter.js +66 -0
  76. package/lib/Auth.js +687 -0
  77. package/lib/AuthDataLock.js +53 -0
  78. package/lib/ClientSDK.js +39 -0
  79. package/lib/Config.js +879 -0
  80. package/lib/Controllers/AdaptableController.js +72 -0
  81. package/lib/Controllers/AnalyticsController.js +43 -0
  82. package/lib/Controllers/CacheController.js +71 -0
  83. package/lib/Controllers/DatabaseController.js +1685 -0
  84. package/lib/Controllers/FilesController.js +122 -0
  85. package/lib/Controllers/HooksController.js +254 -0
  86. package/lib/Controllers/LiveQueryController.js +72 -0
  87. package/lib/Controllers/LoggerController.js +222 -0
  88. package/lib/Controllers/ParseGraphQLController.js +294 -0
  89. package/lib/Controllers/PushController.js +224 -0
  90. package/lib/Controllers/SchemaController.js +1563 -0
  91. package/lib/Controllers/UserController.js +364 -0
  92. package/lib/Controllers/index.js +251 -0
  93. package/lib/Controllers/types.js +2 -0
  94. package/lib/Deprecator/Deprecations.js +100 -0
  95. package/lib/Deprecator/Deprecator.js +140 -0
  96. package/lib/Error.js +50 -0
  97. package/lib/FileUrlValidator.js +69 -0
  98. package/lib/GraphQL/ParseGraphQLSchema.js +375 -0
  99. package/lib/GraphQL/ParseGraphQLServer.js +241 -0
  100. package/lib/GraphQL/helpers/objectsMutations.js +30 -0
  101. package/lib/GraphQL/helpers/objectsQueries.js +246 -0
  102. package/lib/GraphQL/helpers/queryComplexity.js +138 -0
  103. package/lib/GraphQL/loaders/configMutations.js +87 -0
  104. package/lib/GraphQL/loaders/configQueries.js +79 -0
  105. package/lib/GraphQL/loaders/defaultGraphQLMutations.js +21 -0
  106. package/lib/GraphQL/loaders/defaultGraphQLQueries.js +23 -0
  107. package/lib/GraphQL/loaders/defaultGraphQLTypes.js +1099 -0
  108. package/lib/GraphQL/loaders/defaultRelaySchema.js +53 -0
  109. package/lib/GraphQL/loaders/filesMutations.js +107 -0
  110. package/lib/GraphQL/loaders/functionsMutations.js +77 -0
  111. package/lib/GraphQL/loaders/parseClassMutations.js +267 -0
  112. package/lib/GraphQL/loaders/parseClassQueries.js +126 -0
  113. package/lib/GraphQL/loaders/parseClassTypes.js +493 -0
  114. package/lib/GraphQL/loaders/schemaDirectives.js +62 -0
  115. package/lib/GraphQL/loaders/schemaMutations.js +161 -0
  116. package/lib/GraphQL/loaders/schemaQueries.js +80 -0
  117. package/lib/GraphQL/loaders/schemaTypes.js +341 -0
  118. package/lib/GraphQL/loaders/usersMutations.js +433 -0
  119. package/lib/GraphQL/loaders/usersQueries.js +90 -0
  120. package/lib/GraphQL/parseGraphQLUtils.js +71 -0
  121. package/lib/GraphQL/transformers/className.js +14 -0
  122. package/lib/GraphQL/transformers/constraintType.js +53 -0
  123. package/lib/GraphQL/transformers/inputType.js +51 -0
  124. package/lib/GraphQL/transformers/mutation.js +280 -0
  125. package/lib/GraphQL/transformers/outputType.js +51 -0
  126. package/lib/GraphQL/transformers/query.js +237 -0
  127. package/lib/GraphQL/transformers/schemaFields.js +99 -0
  128. package/lib/InstallationDedup.js +178 -0
  129. package/lib/KeyPromiseQueue.js +48 -0
  130. package/lib/LiveQuery/Client.js +90 -0
  131. package/lib/LiveQuery/Id.js +20 -0
  132. package/lib/LiveQuery/ParseCloudCodePublisher.js +54 -0
  133. package/lib/LiveQuery/ParseLiveQueryServer.js +1071 -0
  134. package/lib/LiveQuery/ParsePubSub.js +37 -0
  135. package/lib/LiveQuery/ParseWebSocketServer.js +66 -0
  136. package/lib/LiveQuery/QueryTools.js +443 -0
  137. package/lib/LiveQuery/RequestSchema.js +161 -0
  138. package/lib/LiveQuery/SessionTokenCache.js +51 -0
  139. package/lib/LiveQuery/Subscription.js +47 -0
  140. package/lib/LiveQuery/equalObjects.js +50 -0
  141. package/lib/Options/Definitions.js +1599 -0
  142. package/lib/Options/docs.js +389 -0
  143. package/lib/Options/index.js +12 -0
  144. package/lib/Options/parsers.js +89 -0
  145. package/lib/Page.js +44 -0
  146. package/lib/ParseMessageQueue.js +24 -0
  147. package/lib/ParseServer.js +632 -0
  148. package/lib/ParseServerRESTController.js +173 -0
  149. package/lib/PromiseRouter.js +208 -0
  150. package/lib/Push/PushQueue.js +67 -0
  151. package/lib/Push/PushWorker.js +101 -0
  152. package/lib/Push/utils.js +129 -0
  153. package/lib/RestQuery.js +1208 -0
  154. package/lib/RestWrite.js +1671 -0
  155. package/lib/Routers/AggregateRouter.js +150 -0
  156. package/lib/Routers/AnalyticsRouter.js +26 -0
  157. package/lib/Routers/AudiencesRouter.js +54 -0
  158. package/lib/Routers/ClassesRouter.js +191 -0
  159. package/lib/Routers/CloudCodeRouter.js +87 -0
  160. package/lib/Routers/FeaturesRouter.js +72 -0
  161. package/lib/Routers/FilesRouter.js +772 -0
  162. package/lib/Routers/FunctionsRouter.js +341 -0
  163. package/lib/Routers/GlobalConfigRouter.js +123 -0
  164. package/lib/Routers/GraphQLRouter.js +41 -0
  165. package/lib/Routers/HooksRouter.js +121 -0
  166. package/lib/Routers/IAPValidationRouter.js +113 -0
  167. package/lib/Routers/InstallationsRouter.js +46 -0
  168. package/lib/Routers/LogsRouter.js +57 -0
  169. package/lib/Routers/PagesRouter.js +676 -0
  170. package/lib/Routers/PurgeRouter.js +45 -0
  171. package/lib/Routers/PushRouter.js +75 -0
  172. package/lib/Routers/RolesRouter.js +33 -0
  173. package/lib/Routers/SchemasRouter.js +118 -0
  174. package/lib/Routers/SecurityRouter.js +34 -0
  175. package/lib/Routers/SessionsRouter.js +126 -0
  176. package/lib/Routers/UsersRouter.js +733 -0
  177. package/lib/SchemaMigrations/DefinedSchemas.js +379 -0
  178. package/lib/SchemaMigrations/Migrations.js +30 -0
  179. package/lib/Security/Check.js +109 -0
  180. package/lib/Security/CheckGroup.js +44 -0
  181. package/lib/Security/CheckGroups/CheckGroupDatabase.js +44 -0
  182. package/lib/Security/CheckGroups/CheckGroupServerConfig.js +160 -0
  183. package/lib/Security/CheckGroups/CheckGroups.js +21 -0
  184. package/lib/Security/CheckRunner.js +213 -0
  185. package/lib/SharedRest.js +34 -0
  186. package/lib/StatusHandler.js +329 -0
  187. package/lib/TestUtils.js +87 -0
  188. package/lib/Utils.js +577 -0
  189. package/lib/batch.js +185 -0
  190. package/lib/cache.js +12 -0
  191. package/lib/cli/definitions/parse-live-query-server.js +9 -0
  192. package/lib/cli/definitions/parse-server.js +9 -0
  193. package/lib/cli/parse-live-query-server.js +14 -0
  194. package/lib/cli/parse-server.js +101 -0
  195. package/lib/cli/utils/commander.js +132 -0
  196. package/lib/cli/utils/runner.js +53 -0
  197. package/lib/cloud-code/Parse.Cloud.js +797 -0
  198. package/lib/cloud-code/Parse.Server.js +21 -0
  199. package/lib/cryptoUtils.js +54 -0
  200. package/lib/defaults.js +58 -0
  201. package/lib/deprecated.js +12 -0
  202. package/lib/index.js +89 -0
  203. package/lib/logger.js +40 -0
  204. package/lib/middlewares.js +810 -0
  205. package/lib/password.js +40 -0
  206. package/lib/request.js +175 -0
  207. package/lib/requiredParameter.js +11 -0
  208. package/lib/rest.js +264 -0
  209. package/lib/triggers.js +949 -0
  210. package/lib/vendor/README.md +8 -0
  211. package/lib/vendor/mongodbUrl.js +1012 -0
  212. package/package.json +172 -0
  213. package/postinstall.js +38 -0
  214. package/public/custom_json.html +17 -0
  215. package/public/custom_json.json +23 -0
  216. package/public/custom_page.html +15 -0
  217. package/public/de/email_verification_link_expired.html +24 -0
  218. package/public/de/email_verification_link_invalid.html +21 -0
  219. package/public/de/email_verification_send_fail.html +21 -0
  220. package/public/de/email_verification_send_success.html +19 -0
  221. package/public/de/email_verification_success.html +18 -0
  222. package/public/de/password_reset.html +65 -0
  223. package/public/de/password_reset_link_invalid.html +19 -0
  224. package/public/de/password_reset_success.html +18 -0
  225. package/public/de-AT/email_verification_link_expired.html +24 -0
  226. package/public/de-AT/email_verification_link_invalid.html +21 -0
  227. package/public/de-AT/email_verification_send_fail.html +21 -0
  228. package/public/de-AT/email_verification_send_success.html +19 -0
  229. package/public/de-AT/email_verification_success.html +18 -0
  230. package/public/de-AT/password_reset.html +65 -0
  231. package/public/de-AT/password_reset_link_invalid.html +19 -0
  232. package/public/de-AT/password_reset_success.html +18 -0
  233. package/public/email_verification_link_expired.html +24 -0
  234. package/public/email_verification_link_invalid.html +21 -0
  235. package/public/email_verification_send_fail.html +21 -0
  236. package/public/email_verification_send_success.html +19 -0
  237. package/public/email_verification_success.html +18 -0
  238. package/public/password_reset.html +65 -0
  239. package/public/password_reset_link_invalid.html +19 -0
  240. package/public/password_reset_success.html +18 -0
  241. package/types/@types/@parse/fs-files-adapter/index.d.ts +5 -0
  242. package/types/@types/deepcopy/index.d.ts +5 -0
  243. package/types/LiveQuery/ParseLiveQueryServer.d.ts +40 -0
  244. package/types/Options/index.d.ts +320 -0
  245. package/types/ParseServer.d.ts +65 -0
  246. package/types/eslint.config.mjs +30 -0
  247. package/types/index.d.ts +21 -0
  248. package/types/logger.d.ts +2 -0
  249. package/types/tests.ts +44 -0
  250. package/types/tsconfig.json +24 -0
  251. package/views/choose_password +215 -0
package/README.md ADDED
@@ -0,0 +1,1311 @@
1
+ ![parse-repository-header-server](https://user-images.githubusercontent.com/5673677/138278489-7d0cebc5-1e31-4d3c-8ffb-53efcda6f29d.png)
2
+
3
+ ---
4
+
5
+ [![Build Status](https://github.com/parse-community/parse-server/actions/workflows/ci.yml/badge.svg?branch=alpha)](https://github.com/parse-community/parse-server/actions/workflows/ci.yml?query=workflow%3Aci+branch%3Aalpha)
6
+ [![Build Status](https://github.com/parse-community/parse-server/actions/workflows/ci.yml/badge.svg?branch=release)](https://github.com/parse-community/parse-server/actions/workflows/ci.yml?query=workflow%3Aci+branch%3Arelease)
7
+ [![Snyk Badge](https://snyk.io/test/github/parse-community/parse-server/badge.svg)](https://snyk.io/test/github/parse-community/parse-server)
8
+ [![Coverage](https://codecov.io/github/parse-community/parse-server/branch/alpha/graph/badge.svg)](https://app.codecov.io/github/parse-community/parse-server/tree/alpha)
9
+ [![auto-release](https://img.shields.io/badge/%F0%9F%9A%80-auto--release-9e34eb.svg)](https://github.com/parse-community/parse-dashboard/releases)
10
+
11
+ [![Node Version](https://img.shields.io/badge/nodejs-20,_22,_24-green.svg?logo=node.js&style=flat)](https://nodejs.org)
12
+ [![MongoDB Version](https://img.shields.io/badge/mongodb-7,_8-green.svg?logo=mongodb&style=flat)](https://www.mongodb.com)
13
+ [![Postgres Version](https://img.shields.io/badge/postgresql-16,_17,_18-green.svg?logo=postgresql&style=flat)](https://www.postgresql.org)
14
+
15
+ [![npm latest version](https://img.shields.io/npm/v/parse-server/latest.svg)](https://www.npmjs.com/package/parse-server)
16
+ [![npm alpha version](https://img.shields.io/npm/v/parse-server/alpha.svg)](https://www.npmjs.com/package/parse-server)
17
+
18
+ [![Backers on Open Collective](https://opencollective.com/parse-server/backers/badge.svg)][open-collective-link]
19
+ [![Sponsors on Open Collective](https://opencollective.com/parse-server/sponsors/badge.svg)][open-collective-link]
20
+ [![Forum](https://img.shields.io/discourse/https/community.parseplatform.org/topics.svg)](https://community.parseplatform.org/c/parse-server)
21
+ [![Twitter](https://img.shields.io/twitter/follow/ParsePlatform.svg?label=Follow&style=social)](https://twitter.com/intent/follow?screen_name=ParsePlatform)
22
+ [![Chat](https://img.shields.io/badge/Chat-Join!-%23fff?style=social&logo=slack)](https://chat.parseplatform.org)
23
+
24
+ ---
25
+
26
+ Parse Server is an open source backend that can be deployed to any infrastructure that can run Node.js. Parse Server works with the Express web application framework. It can be added to existing web applications, or run by itself.
27
+
28
+ The full documentation for Parse Server is available in the [wiki](https://github.com/parse-community/parse-server/wiki). The [Parse Server guide](http://docs.parseplatform.org/parse-server/guide/) is a good place to get started. An [API reference](http://parseplatform.org/parse-server/api/) and [Cloud Code guide](https://docs.parseplatform.org/cloudcode/guide/) are also available. If you're interested in developing for Parse Server, the [Development guide](http://docs.parseplatform.org/parse-server/guide/#development-guide) will help you get set up.
29
+
30
+ ---
31
+
32
+ A big _thank you_ 🙏 to our [sponsors](#sponsors) and [backers](#backers) who support the development of Parse Platform!
33
+
34
+ #### Bronze Sponsors
35
+
36
+ [![Bronze Sponsors](https://opencollective.com/parse-server/tiers/bronze-sponsor.svg?avatarHeight=36&button=false)](https://opencollective.com/parse-server/contribute/bronze-sponsor-10559)
37
+
38
+ ---
39
+
40
+ - [Flavors \& Branches](#flavors--branches)
41
+ - [Long Term Support](#long-term-support)
42
+ - [Getting Started](#getting-started)
43
+ - [Running Parse Server](#running-parse-server)
44
+ - [Compatibility](#compatibility)
45
+ - [Node.js](#nodejs)
46
+ - [MongoDB](#mongodb)
47
+ - [PostgreSQL](#postgresql)
48
+ - [Locally](#locally)
49
+ - [Docker Container](#docker-container)
50
+ - [Saving and Querying Objects](#saving-and-querying-objects)
51
+ - [Connect an SDK](#connect-an-sdk)
52
+ - [Running Parse Server elsewhere](#running-parse-server-elsewhere)
53
+ - [Sample Application](#sample-application)
54
+ - [Parse Server + Express](#parse-server--express)
55
+ - [Parse Server Health](#parse-server-health)
56
+ - [Status Values](#status-values)
57
+ - [Configuration](#configuration)
58
+ - [Basic Options](#basic-options)
59
+ - [Client Key Options](#client-key-options)
60
+ - [Access Scopes](#access-scopes)
61
+ - [Route Allow List](#route-allow-list)
62
+ - [Covered Routes](#covered-routes)
63
+ - [Email Verification and Password Reset](#email-verification-and-password-reset)
64
+ - [Password and Account Policy](#password-and-account-policy)
65
+ - [Custom Routes](#custom-routes)
66
+ - [Example](#example)
67
+ - [Reserved Paths](#reserved-paths)
68
+ - [Parameters](#parameters)
69
+ - [Custom Pages](#custom-pages)
70
+ - [Using Environment Variables](#using-environment-variables)
71
+ - [Available Adapters](#available-adapters)
72
+ - [Configuring File Adapters](#configuring-file-adapters)
73
+ - [Restricting File URL Domains](#restricting-file-url-domains)
74
+ - [Idempotency Enforcement](#idempotency-enforcement)
75
+ - [Installations](#installations)
76
+ - [Localization](#localization)
77
+ - [Pages](#pages)
78
+ - [Localization with Directory Structure](#localization-with-directory-structure)
79
+ - [Localization with JSON Resource](#localization-with-json-resource)
80
+ - [Dynamic placeholders](#dynamic-placeholders)
81
+ - [Reserved Keys](#reserved-keys)
82
+ - [Parameters](#parameters-1)
83
+ - [Multi-Tenancy](#multi-tenancy)
84
+ - [Logging](#logging)
85
+ - [Deprecations](#deprecations)
86
+ - [Live Query](#live-query)
87
+ - [GraphQL](#graphql)
88
+ - [Running](#running)
89
+ - [Using the CLI](#using-the-cli)
90
+ - [Using Docker](#using-docker)
91
+ - [Using Express.js](#using-expressjs)
92
+ - [Checking the API health](#checking-the-api-health)
93
+ - [Creating your first class](#creating-your-first-class)
94
+ - [Using automatically generated operations](#using-automatically-generated-operations)
95
+ - [Customizing your GraphQL Schema](#customizing-your-graphql-schema)
96
+ - [Learning more](#learning-more)
97
+ - [Contributing](#contributing)
98
+ - [Contributors](#contributors)
99
+ - [Sponsors](#sponsors)
100
+ - [Backers](#backers)
101
+
102
+ # Flavors & Branches
103
+
104
+ Parse Server is available in different flavors on different branches:
105
+
106
+ - The main branches are [release][log_release] and [alpha][log_alpha]. See the [changelog overview](CHANGELOG.md) for details.
107
+ - The long-term-support (LTS) branches are named `release-<version>.x.x`, for example `release-5.x.x`. LTS branches do not have pre-release branches.
108
+
109
+ ## Long Term Support
110
+
111
+ Long-Term-Support (LTS) is provided for the previous Parse Server major version. For example, Parse Server 5.x will receive security updates until Parse Server 6.x is superseded by Parse Server 7.x and becomes the new LTS version. While the current major version is published on branch `release`, a LTS version is published on branch `release-#.x.x`, for example `release-5.x.x` for the Parse Server 5.x LTS branch.
112
+
113
+ ⚠️ LTS versions are provided to help you transition as soon as possible to the current major version. While we aim to fix security vulnerabilities in the LTS version, our main focus is on developing the current major version and preparing the next major release. Therefore we may leave certain vulnerabilities up to the community to fix. Search for [pull requests with the specific LTS base branch](https://github.com/parse-community/parse-server/pulls?q=is%3Aopen+is%3Apr+base%3Arelease-5.x.x) to see the current open vulnerabilities for that LTS branch.
114
+
115
+ # Getting Started
116
+
117
+ The fastest and easiest way to get started is to run MongoDB and Parse Server locally.
118
+
119
+ ## Running Parse Server
120
+
121
+ Before you start make sure you have installed:
122
+
123
+ - [NodeJS](https://www.npmjs.com/) that includes `npm`
124
+ - [MongoDB](https://www.mongodb.com/) or [PostgreSQL](https://www.postgresql.org/)(with [PostGIS](https://postgis.net) 2.2.0 or higher)
125
+ - Optionally [Docker](https://www.docker.com/)
126
+
127
+ ### Compatibility
128
+
129
+ #### Node.js
130
+
131
+ Parse Server is continuously tested with the most recent releases of Node.js to ensure compatibility. We follow the [Node.js Long Term Support plan](https://github.com/nodejs/Release) and only test against versions that are officially supported and have not reached their end-of-life date.
132
+
133
+ | Version | Minimum Version | End-of-Life | Parse Server Support |
134
+ | ---------- | --------------- | ----------- | -------------------- |
135
+ | Node.js 18 | 18.20.4 | April 2025 | <= 8.x (2025) |
136
+ | Node.js 20 | 20.19.0 | April 2026 | <= 9.x (2026) |
137
+ | Node.js 22 | 22.12.0 | April 2027 | <= 10.x (2027) |
138
+ | Node.js 24 | 24.11.0 | April 2028 | <= 11.x (2028) |
139
+
140
+ #### MongoDB
141
+
142
+ Parse Server is continuously tested with the most recent releases of MongoDB to ensure compatibility. We follow the [MongoDB support schedule](https://www.mongodb.com/support-policy) and [MongoDB lifecycle schedule](https://www.mongodb.com/support-policy/lifecycles) and only test against versions that are officially supported and have not reached their end-of-life date. MongoDB "rapid releases" are ignored as these are considered pre-releases of the next major version.
143
+
144
+ | Version | Minimum Version | End-of-Life | Parse Server Support |
145
+ | --------- | --------------- | ----------- | -------------------- |
146
+ | MongoDB 6 | 6.0.19 | July 2025 | <= 8.x (2025) |
147
+ | MongoDB 7 | 7.0.16 | August 2026 | <= 9.x (2026) |
148
+ | MongoDB 8 | 8.0.4 | TDB | <= 10.x (2027) |
149
+
150
+ #### PostgreSQL
151
+
152
+ Parse Server is continuously tested with the most recent releases of PostgreSQL and PostGIS to ensure compatibility, using [PostGIS docker images](https://registry.hub.docker.com/r/postgis/postgis/tags?page=1&ordering=last_updated). We follow the [PostgreSQL support schedule](https://www.postgresql.org/support/versioning) and [PostGIS support schedule](https://www.postgis.net/eol_policy/) and only test against versions that are officially supported and have not reached their end-of-life date. Due to the extensive PostgreSQL support duration of 5 years, Parse Server drops support about 2 years before the official end-of-life date.
153
+
154
+ | Version | PostGIS Version | End-of-Life | Parse Server Support |
155
+ | ----------- | ----------------------- | ------------- | -------------------- |
156
+ | Postgres 13 | 3.1, 3.2, 3.3, 3.4, 3.5 | November 2025 | <= 6.x (2023) |
157
+ | Postgres 14 | 3.5 | November 2026 | <= 7.x (2024) |
158
+ | Postgres 15 | 3.3, 3.4, 3.5 | November 2027 | <= 8.x (2025) |
159
+ | Postgres 16 | 3.5 | November 2028 | <= 9.x (2026) |
160
+ | Postgres 17 | 3.5 | November 2029 | <= 10.x (2027) |
161
+ | Postgres 18 | 3.6 | November 2030 | <= 11.x (2028) |
162
+
163
+ ### Locally
164
+
165
+ ```bash
166
+ $ npm install -g parse-server mongodb-runner
167
+ $ mongodb-runner start
168
+ $ parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --databaseURI mongodb://localhost/test
169
+ ```
170
+
171
+ **_Note:_** _If installation with_ `-g` _fails due to permission problems_ (`npm ERR! code 'EACCES'`), _please refer to [this link](https://docs.npmjs.com/getting-started/fixing-npm-permissions)._
172
+
173
+ ### Docker Container
174
+
175
+ ```bash
176
+ $ git clone https://github.com/parse-community/parse-server
177
+ $ cd parse-server
178
+ $ docker build --tag parse-server .
179
+ $ docker run --name my-mongo -d mongo
180
+ ```
181
+
182
+ #### Running the Parse Server Image <!-- omit in toc -->
183
+
184
+ ```bash
185
+ $ docker run --name my-parse-server -v config-vol:/parse-server/config -p 1337:1337 --link my-mongo:mongo -d parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --databaseURI mongodb://mongo/test
186
+ ```
187
+
188
+ **_Note:_** _If you want to use [Cloud Code](https://docs.parseplatform.org/cloudcode/guide/), add `-v cloud-code-vol:/parse-server/cloud --cloud /parse-server/cloud/main.js` to the command above. Make sure `main.js` is in the `cloud-code-vol` directory before starting Parse Server._
189
+
190
+ You can use any arbitrary string as your application id and master key. These will be used by your clients to authenticate with the Parse Server.
191
+
192
+ That's it! You are now running a standalone version of Parse Server on your machine.
193
+
194
+ **Using a remote MongoDB?** Pass the `--databaseURI DATABASE_URI` parameter when starting `parse-server`. Learn more about configuring Parse Server [here](#configuration). For a full list of available options, run `parse-server --help`.
195
+
196
+ ### Saving and Querying Objects
197
+
198
+ Now that you're running Parse Server, it is time to save your first object. The easiest way is to use the [REST API](http://docs.parseplatform.org/rest/guide), but you can easily do the same using any of the [Parse SDKs](http://parseplatform.org/#sdks). To learn more check out the [documentation](http://docs.parseplatform.org).
199
+
200
+ ### Connect an SDK
201
+
202
+ Parse provides SDKs for all the major platforms. Refer to the Parse Server guide to [learn how to connect your app to Parse Server](https://docs.parseplatform.org/parse-server/guide/#using-parse-sdks-with-parse-server).
203
+
204
+ ## Running Parse Server elsewhere
205
+
206
+ Once you have a better understanding of how the project works, please refer to the [Parse Server wiki](https://github.com/parse-community/parse-server/wiki) for in-depth guides to deploy Parse Server to major infrastructure providers. Read on to learn more about additional ways of running Parse Server.
207
+
208
+ ### Sample Application
209
+
210
+ We have provided a basic [Node.js application](https://github.com/parse-community/parse-server-example) that uses the Parse Server module on Express and can be easily deployed to various infrastructure providers:
211
+
212
+ - [Heroku and mLab](https://devcenter.heroku.com/articles/deploying-a-parse-server-to-heroku)
213
+ - [AWS and Elastic Beanstalk](http://mobile.awsblog.com/post/TxCD57GZLM2JR/How-to-set-up-Parse-Server-on-AWS-using-AWS-Elastic-Beanstalk)
214
+ - [Google App Engine](https://medium.com/@justinbeckwith/deploying-parse-server-to-google-app-engine-6bc0b7451d50)
215
+ - [Microsoft Azure](https://azure.microsoft.com/en-us/blog/azure-welcomes-parse-developers/)
216
+ - [SashiDo](https://blog.sashido.io/tag/migration/)
217
+ - [Digital Ocean](https://www.digitalocean.com/community/tutorials/how-to-run-parse-server-on-ubuntu-14-04)
218
+ - [Pivotal Web Services](https://github.com/cf-platform-eng/pws-parse-server)
219
+ - [Back4app](https://www.back4app.com/docs/get-started/welcome)
220
+ - [Glitch](https://glitch.com/edit/#!/parse-server)
221
+ - [Flynn](https://flynn.io/blog/parse-apps-on-flynn)
222
+ - [Elestio](https://elest.io/open-source/parse)
223
+
224
+ ### Parse Server + Express
225
+
226
+ You can also create an instance of Parse Server, and mount it on a new or existing Express website:
227
+
228
+ ```js
229
+ const express = require('express');
230
+ const ParseServer = require('parse-server').ParseServer;
231
+ const app = express();
232
+
233
+ const server = new ParseServer({
234
+ databaseURI: 'mongodb://localhost:27017/dev', // Connection string for your MongoDB database
235
+ cloud: './cloud/main.js', // Path to your Cloud Code
236
+ appId: 'myAppId',
237
+ masterKey: 'myMasterKey', // Keep this key secret!
238
+ fileKey: 'optionalFileKey',
239
+ serverURL: 'http://localhost:1337/parse', // Don't forget to change to https if needed
240
+ });
241
+
242
+ // Start server
243
+ await server.start();
244
+
245
+ // Serve the Parse API on the /parse URL prefix
246
+ app.use('/parse', server.app);
247
+
248
+ app.listen(1337, function () {
249
+ console.log('parse-server-example running on port 1337.');
250
+ });
251
+ ```
252
+
253
+ For a full list of available options, run `parse-server --help` or take a look at [Parse Server Configurations][server-options].
254
+
255
+ ## Parse Server Health
256
+
257
+ Check the Parse Server health by sending a request to the `/parse/health` endpoint.
258
+
259
+ The response looks like this:
260
+
261
+ ```json
262
+ {
263
+ "status": "ok"
264
+ }
265
+ ```
266
+
267
+ ### Status Values
268
+
269
+ | Value | Description |
270
+ | ------------- | --------------------------------------------------------------------------- |
271
+ | `initialized` | The server has been created but the `start` method has not been called yet. |
272
+ | `starting` | The server is starting up. |
273
+ | `ok` | The server started and is running. |
274
+ | `error` | There was a startup error, see the logs for details. |
275
+
276
+ # Configuration
277
+
278
+ Parse Server can be configured using the following options. You may pass these as parameters when running a standalone `parse-server`, or by loading a configuration file in JSON format using `parse-server path/to/configuration.json`. If you're using Parse Server on Express, you may also pass these to the `ParseServer` object as options.
279
+
280
+ For the full list of available options, run `parse-server --help` or take a look at [Parse Server Configurations][server-options].
281
+
282
+ ## Basic Options
283
+
284
+ - `appId` **(required)** - The application id to host with this server instance. You can use any arbitrary string. For migrated apps, this should match your hosted Parse app.
285
+ - `masterKey` **(required)** - The master key to use for overriding ACL security. You can use any arbitrary string. Keep it secret! For migrated apps, this should match your hosted Parse app.
286
+ - `databaseURI` **(required)** - The connection string for your database, i.e. `mongodb://user:pass@host.com/dbname`. Be sure to [URL encode your password](https://app.zencoder.com/docs/guides/getting-started/special-characters-in-usernames-and-passwords) if your password has special characters.
287
+ - `port` - The default port is 1337, specify this parameter to use a different port.
288
+ - `serverURL` - URL to your Parse Server (don't forget to specify http:// or https://). This URL will be used when making requests to Parse Server from Cloud Code.
289
+ - `cloud` - The absolute path to your cloud code `main.js` file.
290
+ - `push` - Configuration options for APNS and FCM push. See the [Push Notifications quick start](https://docs.parseplatform.org/parse-server/guide/#push-notifications-quick-start).
291
+
292
+ ## Client Key Options
293
+
294
+ The client keys used with Parse are no longer necessary with Parse Server. If you wish to still require them, perhaps to be able to refuse access to older clients, you can set the keys at initialization time. Setting any of these keys will require all requests to provide one of the configured keys.
295
+
296
+ - `clientKey`
297
+ - `javascriptKey`
298
+ - `restAPIKey`
299
+ - `dotNetKey`
300
+
301
+ ## Access Scopes
302
+
303
+ | Scope | Internal data | Read-only data <sub>(1)</sub> | Custom data | Restricted by CLP, ACL | Key |
304
+ | -------------- | ------------- | ----------------------------- | ----------- | ---------------------- | ------------------- |
305
+ | Internal | r/w | r/w | r/w | no | `maintenanceKey` |
306
+ | Master | -/- | r/- | r/w | no | `masterKey` |
307
+ | ReadOnlyMaster | -/- | r/- | r/- | no | `readOnlyMasterKey` |
308
+ | Session | -/- | r/- | r/w | yes | `sessionToken` |
309
+
310
+ <sub>(1) `Parse.Object.createdAt`, `Parse.Object.updatedAt`.</sub>
311
+
312
+ > [!NOTE]
313
+ > In Cloud Code, both `masterKey` and `readOnlyMasterKey` set `request.master` to `true`. To distinguish between them, check `request.isReadOnly`. For example, use `request.master && !request.isReadOnly` to ensure full master key access.
314
+
315
+ ## Route Allow List
316
+
317
+ The `routeAllowList` option restricts which API routes are accessible to external clients. When set, all external requests are denied by default unless the route matches one of the configured regex patterns. This is useful for apps where all logic runs in Cloud Code and clients should not access the API directly.
318
+
319
+ Internal calls from Cloud Code, Cloud Jobs, and triggers are not affected. Master key and maintenance key requests bypass the restriction.
320
+
321
+ ```js
322
+ const server = ParseServer({
323
+ ...otherOptions,
324
+ routeAllowList: [
325
+ 'classes/ChatMessage',
326
+ 'classes/Public.*',
327
+ 'users',
328
+ 'login',
329
+ 'functions/getMenu',
330
+ 'health',
331
+ ],
332
+ });
333
+ ```
334
+
335
+ Each entry is a regex pattern matched against the normalized route identifier. Patterns are auto-anchored with `^` and `$` for full-match semantics. For example, `classes/Chat` matches only `classes/Chat`, not `classes/ChatRoom`. Use `classes/Chat.*` to match both.
336
+
337
+ Setting an empty array `[]` blocks all external non-master-key requests (full lockdown). Not setting the option preserves current behavior (all routes accessible).
338
+
339
+ ### Covered Routes
340
+
341
+ The following table lists all route groups covered by `routeAllowList` with examples of how to allow them.
342
+
343
+ | Route group | Example route identifiers | Allow pattern |
344
+ | --- | --- | --- |
345
+ | **Data** | | |
346
+ | Classes | `classes/[className]`, `classes/[className]/[objectId]` | `classes/[className].*` |
347
+ | Aggregate | `aggregate/[className]` | `aggregate/.*` |
348
+ | Batch | `batch` | `batch` |
349
+ | Purge | `purge/[className]` | `purge/.*` |
350
+ | | | |
351
+ | **System Classes** | | |
352
+ | Users | `users`, `users/me`, `users/[objectId]` | `users.*` |
353
+ | Sessions | `sessions`, `sessions/me`, `sessions/[objectId]` | `sessions.*` |
354
+ | Installations | `installations`, `installations/[objectId]` | `installations.*` |
355
+ | Roles | `roles`, `roles/[objectId]` | `roles.*` |
356
+ | | | |
357
+ | **Auth** | | |
358
+ | Login | `login`, `loginAs` | `login.*` |
359
+ | Logout | `logout` | `logout` |
360
+ | Upgrade session | `upgradeToRevocableSession` | `upgradeToRevocableSession` |
361
+ | Auth challenge | `challenge` | `challenge` |
362
+ | Email verification | `verificationEmailRequest` | `verificationEmailRequest` |
363
+ | Password verification | `verifyPassword` | `verifyPassword` |
364
+ | Password reset | `requestPasswordReset` | `requestPasswordReset` |
365
+ | | | |
366
+ | **Cloud Code** | | |
367
+ | Cloud Functions | `functions/[functionName]` | `functions/.*` |
368
+ | Cloud Jobs (trigger) | `jobs`, `jobs/[jobName]` | `jobs.*` |
369
+ | Cloud Jobs (schedule) | `cloud_code/jobs`, `cloud_code/jobs/data`, `cloud_code/jobs/[objectId]` | `cloud_code/.*` |
370
+ | Hooks | `hooks/functions`, `hooks/triggers`, `hooks/functions/[functionName]`, `hooks/triggers/[className]/[triggerName]` | `hooks/.*` |
371
+ | | | |
372
+ | **Push** | | |
373
+ | Push | `push` | `push` |
374
+ | Push audiences | `push_audiences`, `push_audiences/[objectId]` | `push_audiences.*` |
375
+ | | | |
376
+ | **Schema** | | |
377
+ | Schemas | `schemas`, `schemas/[className]` | `schemas.*` |
378
+ | | | |
379
+ | **Config** | | |
380
+ | Config | `config` | `config` |
381
+ | GraphQL config | `graphql-config` | `graphql-config` |
382
+ | | | |
383
+ | **Analytics** | | |
384
+ | Analytics | `events/AppOpened`, `events/[eventName]` | `events/.*` |
385
+ | | | |
386
+ | **Server** | | |
387
+ | Health | `health` | `health` |
388
+ | Server info | `serverInfo` | `serverInfo` |
389
+ | Security | `security` | `security` |
390
+ | Logs | `scriptlog` | `scriptlog` |
391
+ | | | |
392
+ | **Legacy** | | |
393
+ | Purchase validation | `validate_purchase` | `validate_purchase` |
394
+
395
+ > [!NOTE]
396
+ > File routes are not covered by `routeAllowList`. File upload access is controlled via the `fileUpload` option. File download and metadata access is controlled via the `fileDownload` option.
397
+
398
+ ## Email Verification and Password Reset
399
+
400
+ Verifying user email addresses and enabling password reset via email requires an email adapter. There are many email adapters provided and maintained by the community. The following is an example configuration with an example email adapter. See the [Parse Server Options][server-options] for more details and a full list of available options.
401
+
402
+ ```js
403
+ const server = ParseServer({
404
+ ...otherOptions,
405
+
406
+ // Enable email verification
407
+ verifyUserEmails: true,
408
+
409
+ // Set email verification token validity to 2 hours
410
+ emailVerifyTokenValidityDuration: 2 * 60 * 60,
411
+
412
+ // Set email adapter
413
+ emailAdapter: {
414
+ module: 'example-mail-adapter',
415
+ options: {
416
+ // Additional adapter options
417
+ ...mailAdapterOptions,
418
+ },
419
+ },
420
+ });
421
+ ```
422
+
423
+ Offical email adapters maintained by Parse Platform:
424
+
425
+ - [parse-server-api-mail-adapter](https://github.com/parse-community/parse-server-api-mail-adapter) (localization, templates, universally supports any email provider)
426
+
427
+ Email adapters contributed by the community:
428
+
429
+ - [parse-smtp-template](https://www.npmjs.com/package/parse-smtp-template) (localization, templates)
430
+ - [parse-server-postmark-adapter](https://www.npmjs.com/package/parse-server-postmark-adapter)
431
+ - [parse-server-sendgrid-adapter](https://www.npmjs.com/package/parse-server-sendgrid-adapter)
432
+ - [parse-server-mandrill-adapter](https://www.npmjs.com/package/parse-server-mandrill-adapter)
433
+ - [parse-server-simple-ses-adapter](https://www.npmjs.com/package/parse-server-simple-ses-adapter)
434
+ - [parse-server-mailgun-adapter-template](https://www.npmjs.com/package/parse-server-mailgun-adapter-template)
435
+ - [parse-server-sendinblue-adapter](https://www.npmjs.com/package/parse-server-sendinblue-adapter)
436
+ - [parse-server-mailjet-adapter](https://www.npmjs.com/package/parse-server-mailjet-adapter)
437
+ - [simple-parse-smtp-adapter](https://www.npmjs.com/package/simple-parse-smtp-adapter)
438
+ - [parse-server-generic-email-adapter](https://www.npmjs.com/package/parse-server-generic-email-adapter)
439
+
440
+ ## Password and Account Policy
441
+
442
+ Set a password and account policy that meets your security requirements. The following is an example configuration. See the [Parse Server Options][server-options] for more details and a full list of available options.
443
+
444
+ ```js
445
+ const server = ParseServer({
446
+ ...otherOptions,
447
+
448
+ // The account lock policy
449
+ accountLockout: {
450
+ // Lock the account for 5 minutes.
451
+ duration: 5,
452
+ // Lock an account after 3 failed log-in attempts
453
+ threshold: 3,
454
+ // Unlock the account after a successful password reset
455
+ unlockOnPasswordReset: true,
456
+ },
457
+
458
+ // The password policy
459
+ passwordPolicy: {
460
+ // Enforce a password of at least 8 characters which contain at least 1 lower case, 1 upper case and 1 digit
461
+ validatorPattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{8,})/,
462
+ // Do not allow the username as part of the password
463
+ doNotAllowUsername: true,
464
+ // Do not allow to re-use the last 5 passwords when setting a new password
465
+ maxPasswordHistory: 5,
466
+ },
467
+ });
468
+ ```
469
+
470
+ ## Custom Routes
471
+
472
+ Custom routes allow to build user flows with webpages, similar to the existing password reset and email verification features. Custom routes are defined with the `pages` option in the Parse Server configuration:
473
+
474
+ ### Example
475
+
476
+ ```js
477
+ const api = new ParseServer({
478
+ ...otherOptions,
479
+
480
+ pages: {
481
+ customRoutes: [{
482
+ method: 'GET',
483
+ path: 'custom_route',
484
+ handler: async request => {
485
+ // custom logic
486
+ // ...
487
+ // then, depending on the outcome, return a HTML file as response
488
+ return { file: 'custom_page.html' };
489
+ }
490
+ }]
491
+ }
492
+ }
493
+ ```
494
+
495
+ The above route can be invoked by sending a `GET` request to:
496
+ `https://[parseServerPublicUrl]/[parseMount]/[pagesEndpoint]/[appId]/[customRoute]`
497
+
498
+ The `handler` receives the `request` and returns a `custom_page.html` webpage from the `pages.pagesPath` directory as response. The advantage of building a custom route this way is that it automatically makes use of Parse Server's built-in capabilities, such as [page localization](#pages) and [dynamic placeholders](#dynamic-placeholders).
499
+
500
+ ### Reserved Paths
501
+
502
+ The following paths are already used by Parse Server's built-in features and are therefore not available for custom routes. Custom routes with an identical combination of `path` and `method` are ignored.
503
+
504
+ | Path | HTTP Method | Feature |
505
+ | --------------------------- | ----------- | ------------------ |
506
+ | `verify_email` | `GET` | email verification |
507
+ | `resend_verification_email` | `POST` | email verification |
508
+ | `choose_password` | `GET` | password reset |
509
+ | `request_password_reset` | `GET` | password reset |
510
+ | `request_password_reset` | `POST` | password reset |
511
+
512
+ ### Parameters
513
+
514
+ | Parameter | Optional | Type | Default value | Example values | Environment variable | Description |
515
+ | ---------------------------- | -------- | --------------- | ------------- | --------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
516
+ | `pages` | yes | `Object` | `undefined` | - | `PARSE_SERVER_PAGES` | The options for pages such as password reset and email verification. |
517
+ | `pages.customRoutes` | yes | `Array` | `[]` | - | `PARSE_SERVER_PAGES_CUSTOM_ROUTES` | The custom routes. The routes are added in the order they are defined here, which has to be considered since requests traverse routes in an ordered manner. Custom routes are traversed after build-in routes such as password reset and email verification. |
518
+ | `pages.customRoutes.method` | | `String` | - | `GET`, `POST` | - | The HTTP method of the custom route. |
519
+ | `pages.customRoutes.path` | | `String` | - | `custom_page` | - | The path of the custom route. Note that the same path can used if the `method` is different, for example a path `custom_page` can have two routes, a `GET` and `POST` route, which will be invoked depending on the HTTP request method. |
520
+ | `pages.customRoutes.handler` | | `AsyncFunction` | - | `async () => { ... }` | - | The route handler that is invoked when the route matches the HTTP request. If the handler does not return a page, the request is answered with a 404 `Not found.` response. |
521
+
522
+ ## Custom Pages
523
+
524
+ It’s possible to change the default pages of the app and redirect the user to another path or domain.
525
+
526
+ ```js
527
+ const server = ParseServer({
528
+ ...otherOptions,
529
+
530
+ customPages: {
531
+ passwordResetSuccess: 'http://yourapp.com/passwordResetSuccess',
532
+ verifyEmailSuccess: 'http://yourapp.com/verifyEmailSuccess',
533
+ parseFrameURL: 'http://yourapp.com/parseFrameURL',
534
+ linkSendSuccess: 'http://yourapp.com/linkSendSuccess',
535
+ linkSendFail: 'http://yourapp.com/linkSendFail',
536
+ invalidLink: 'http://yourapp.com/invalidLink',
537
+ invalidVerificationLink: 'http://yourapp.com/invalidVerificationLink',
538
+ choosePassword: 'http://yourapp.com/choosePassword',
539
+ },
540
+ });
541
+ ```
542
+
543
+ ## Using Environment Variables
544
+
545
+ You may configure the Parse Server using environment variables:
546
+
547
+ ```bash
548
+ PORT
549
+ PARSE_SERVER_APPLICATION_ID
550
+ PARSE_SERVER_MASTER_KEY
551
+ PARSE_SERVER_DATABASE_URI
552
+ PARSE_SERVER_URL
553
+ PARSE_SERVER_CLOUD
554
+ ```
555
+
556
+ The default port is 1337, to use a different port set the PORT environment variable:
557
+
558
+ ```bash
559
+ $ PORT=8080 parse-server --appId APPLICATION_ID --masterKey MASTER_KEY
560
+ ```
561
+
562
+ For the full list of configurable environment variables, run `parse-server --help` or take a look at [Parse Server Configuration](https://github.com/parse-community/parse-server/blob/master/src/Options/Definitions.js).
563
+
564
+ ## Available Adapters
565
+
566
+ All official adapters are distributed as scoped packages on [npm (@parse)](https://www.npmjs.com/search?q=scope%3Aparse).
567
+
568
+ Some well maintained adapters are also available on the [Parse Server Modules](https://github.com/parse-server-modules) organization.
569
+
570
+ You can also find more adapters maintained by the community by searching on [npm](https://www.npmjs.com/search?q=parse-server%20adapter&page=1&ranking=optimal).
571
+
572
+ ## Configuring File Adapters
573
+
574
+ Parse Server allows developers to choose from several options when hosting files:
575
+
576
+ - `GridFSBucketAdapter` - which is backed by MongoDB
577
+ - `S3Adapter` - which is backed by [Amazon S3](https://aws.amazon.com/s3/)
578
+ - `GCSAdapter` - which is backed by [Google Cloud Storage](https://cloud.google.com/storage/)
579
+ - `FSAdapter` - local file storage
580
+
581
+ `GridFSBucketAdapter` is used by default and requires no setup, but if you're interested in using Amazon S3, Google Cloud Storage, or local file storage, additional configuration information is available in the [Parse Server guide](http://docs.parseplatform.org/parse-server/guide/#configuring-file-adapters).
582
+
583
+ ### Restricting File URL Domains
584
+
585
+ Parse objects can reference files by URL. To prevent [SSRF attacks](https://owasp.org/www-community/attacks/Server_Side_Request_Forgery) via crafted file URLs, you can restrict the allowed URL domains using the `fileUpload.allowedFileUrlDomains` option.
586
+
587
+ This protects against scenarios where an attacker provides a `Parse.File` with an arbitrary URL, for example as a Cloud Function parameter or in a field of type `Object` or `Array`. If Cloud Code or a client calls `getData()` on such a file, the Parse SDK makes an HTTP request to that URL, potentially leaking the server or client IP address and accessing internal services.
588
+
589
+ > [!NOTE]
590
+ > Fields of type `Parse.File` in the Parse schema are not affected by this attack, because Parse Server discards the URL on write and dynamically generates it on read based on the file adapter configuration.
591
+
592
+ ```javascript
593
+ const parseServer = new ParseServer({
594
+ ...otherOptions,
595
+ fileUpload: {
596
+ allowedFileUrlDomains: ['cdn.example.com', '*.example.com'],
597
+ },
598
+ });
599
+ ```
600
+
601
+ | Parameter | Optional | Type | Default | Environment Variable |
602
+ |---|---|---|---|---|
603
+ | `fileUpload.allowedFileUrlDomains` | yes | `String[]` | `['*']` | `PARSE_SERVER_FILE_UPLOAD_ALLOWED_FILE_URL_DOMAINS` |
604
+
605
+ - `['*']` (default) allows file URLs with any domain.
606
+ - `['cdn.example.com']` allows only exact hostname matches.
607
+ - `['*.example.com']` allows any subdomain of `example.com`.
608
+ - `[]` blocks all file URLs; only files referenced by name are allowed.
609
+
610
+ ## Idempotency Enforcement
611
+
612
+ **Caution, this is an experimental feature that may not be appropriate for production.**
613
+
614
+ This feature deduplicates identical requests that are received by Parse Server multiple times, typically due to network issues or network adapter access restrictions on mobile operating systems.
615
+
616
+ Identical requests are identified by their request header `X-Parse-Request-Id`. Therefore a client request has to include this header for deduplication to be applied. Requests that do not contain this header cannot be deduplicated and are processed normally by Parse Server. This means rolling out this feature to clients is seamless as Parse Server still processes requests without this header when this feature is enabled.
617
+
618
+ > This feature needs to be enabled on the client side to send the header and on the server to process the header. Refer to the specific Parse SDK docs to see whether the feature is supported yet.
619
+
620
+ Deduplication is only done for object creation and update (`POST` and `PUT` requests). Deduplication is not done for object finding and deletion (`GET` and `DELETE` requests), as these operations are already idempotent by definition.
621
+
622
+ ### Configuration example <!-- omit in toc -->
623
+
624
+ ```
625
+ let api = new ParseServer({
626
+ idempotencyOptions: {
627
+ paths: [".*"], // enforce for all requests
628
+ ttl: 120 // keep request IDs for 120s
629
+ }
630
+ }
631
+ ```
632
+
633
+ ### Parameters <!-- omit in toc -->
634
+
635
+ | Parameter | Optional | Type | Default value | Example values | Environment variable | Description |
636
+ | -------------------------- | -------- | --------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
637
+ | `idempotencyOptions` | yes | `Object` | `undefined` | | PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_OPTIONS | Setting this enables idempotency enforcement for the specified paths. |
638
+ | `idempotencyOptions.paths` | yes | `Array<String>` | `[]` | `.*` (all paths, includes the examples below), <br>`functions/.*` (all functions), <br>`jobs/.*` (all jobs), <br>`classes/.*` (all classes), <br>`functions/.*` (all functions), <br>`users` (user creation / update), <br>`installations` (installation creation / update) | PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_PATHS | An array of path patterns that have to match the request path for request deduplication to be enabled. The mount path must not be included, for example to match the request path `/parse/functions/myFunction` specify the path pattern `functions/myFunction`. A trailing slash of the request path is ignored, for example the path pattern `functions/myFunction` matches both `/parse/functions/myFunction` and `/parse/functions/myFunction/`. |
639
+ | `idempotencyOptions.ttl` | yes | `Integer` | `300` | `60` (60 seconds) | PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_TTL | The duration in seconds after which a request record is discarded from the database. Duplicate requests due to network issues can be expected to arrive within milliseconds up to several seconds. This value must be greater than `0`. |
640
+
641
+ ### Postgres <!-- omit in toc -->
642
+
643
+ To use this feature in Postgres, you will need to create a cron job using [pgAdmin](https://www.pgadmin.org/docs/pgadmin4/development/pgagent_jobs.html) or similar to call the Postgres function `idempotency_delete_expired_records()` that deletes expired idempotency records. You can find an example script below. Make sure the script has the same privileges to log into Postgres as Parse Server.
644
+
645
+ ```bash
646
+ #!/bin/bash
647
+
648
+ set -e
649
+ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
650
+ SELECT idempotency_delete_expired_records();
651
+ EOSQL
652
+
653
+ exec "$@"
654
+ ```
655
+
656
+ Assuming the script above is named, `parse_idempotency_delete_expired_records.sh`, a cron job that runs the script every 2 minutes may look like:
657
+
658
+ ```bash
659
+ 2 * * * * /root/parse_idempotency_delete_expired_records.sh >/dev/null 2>&1
660
+ ```
661
+
662
+ ## Installations
663
+
664
+ Parse Server deduplicates `_Installation` records when a new install collides with an existing row's `deviceToken`. The `installation` option block configures the dedup behavior.
665
+
666
+ ### Options
667
+
668
+ | Parameter | Optional | Type | Default | Environment Variable |
669
+ |---|---|---|---|---|
670
+ | `installation.duplicateDeviceTokenActionEnforceAuth` | yes | `Boolean` | `false` | `PARSE_SERVER_INSTALLATION_DUPLICATE_DEVICE_TOKEN_ACTION_ENFORCE_AUTH` |
671
+ | `installation.duplicateDeviceTokenAction` | yes | `String` | `'delete'` | `PARSE_SERVER_INSTALLATION_DUPLICATE_DEVICE_TOKEN_ACTION` |
672
+ | `installation.duplicateDeviceTokenMergePriority` | yes | `String` | `'deviceToken'` | `PARSE_SERVER_INSTALLATION_DUPLICATE_DEVICE_TOKEN_MERGE_PRIORITY` |
673
+
674
+ #### `duplicateDeviceTokenActionEnforceAuth`
675
+
676
+ When `true`, the dedup operation runs with the caller's auth context so ACL and CLP are honored. When `false`, the dedup runs as master and bypasses both. Master and maintenance keys always bypass regardless of this flag.
677
+
678
+ #### `duplicateDeviceTokenAction`
679
+
680
+ What Parse Server does to the conflicting `_Installation` row(s) when a new install's `deviceToken` collides with an existing row.
681
+
682
+ - `'delete'`: destroys the conflicting row.
683
+ - `'update'`: clears the now-conflicting ID field on the conflicting row, preserving custom fields, channels, and history.
684
+
685
+ #### `duplicateDeviceTokenMergePriority`
686
+
687
+ When an existing row holds the new `deviceToken` but has no `installationId` of its own, Parse Server merges the two rows. This option controls which side wins.
688
+
689
+ - `'deviceToken'`: the deviceToken-only row survives; the request's installationId-matched row is the loser.
690
+ - `'installationId'`: the request's installationId-matched row survives; the deviceToken-only orphan is the loser.
691
+
692
+ ### Configuration example
693
+
694
+ ```javascript
695
+ const parseServer = new ParseServer({
696
+ ...otherOptions,
697
+ installation: {
698
+ duplicateDeviceTokenActionEnforceAuth: true,
699
+ duplicateDeviceTokenAction: 'update',
700
+ duplicateDeviceTokenMergePriority: 'installationId',
701
+ },
702
+ });
703
+ ```
704
+
705
+ ## Localization
706
+
707
+ ### Pages
708
+
709
+ Custom pages as well as feature pages (e.g. password reset, email verification) can be localized with the `pages` option in the Parse Server configuration:
710
+
711
+ ```js
712
+ const api = new ParseServer({
713
+ ...otherOptions,
714
+
715
+ pages: {
716
+ enableLocalization: true,
717
+ }
718
+ }
719
+ ```
720
+
721
+ Localization is achieved by matching a request-supplied `locale` parameter with localized page content. The locale can be supplied in either the request query, body or header with the following keys:
722
+
723
+ - query: `locale`
724
+ - body: `locale`
725
+ - header: `x-parse-page-param-locale`
726
+
727
+ For example, a password reset link with the locale parameter in the query could look like this:
728
+
729
+ ```
730
+ http://example.com/parse/apps/[appId]/request_password_reset?token=[token]&username=[username]&locale=de-AT
731
+ ```
732
+
733
+ - Localization is only available for pages in the pages directory as set with `pages.pagesPath`.
734
+ - Localization for feature pages (e.g. password reset, email verification) is disabled if `pages.customUrls` are set, even if the custom URLs point to the pages within the pages path.
735
+ - Only `.html` files are considered for localization when localizing custom pages.
736
+
737
+ Pages can be localized in two ways:
738
+
739
+ #### Localization with Directory Structure
740
+
741
+ Pages are localized by using the corresponding file in the directory structure where the files are placed in subdirectories named after the locale or language. The file in the base directory is the default file.
742
+
743
+ **Example Directory Structure:**
744
+
745
+ ```js
746
+ root/
747
+ ├── public/ // pages base path
748
+ │ ├── example.html // default file
749
+ │ └── de/ // de language folder
750
+ │ │ └── example.html // de localized file
751
+ │ └── de-AT/ // de-AT locale folder
752
+ │ │ └── example.html // de-AT localized file
753
+ ```
754
+
755
+ Files are matched with the locale in the following order:
756
+
757
+ 1. Locale match, e.g. locale `de-AT` matches file in folder `de-AT`.
758
+ 1. Language match, e.g. locale `de-CH` matches file in folder `de`.
759
+ 1. Default; file in base folder is returned.
760
+
761
+ **Configuration Example:**
762
+
763
+ ```js
764
+ const api = new ParseServer({
765
+ ...otherOptions,
766
+
767
+ pages: {
768
+ enableLocalization: true,
769
+ customUrls: {
770
+ passwordReset: 'https://example.com/page.html'
771
+ }
772
+ }
773
+ }
774
+ ```
775
+
776
+ Pros:
777
+
778
+ - All files are complete in their content and can be easily opened and previewed by viewing the file in a browser.
779
+
780
+ Cons:
781
+
782
+ - In most cases, a localized page differs only slightly from the default page, which could cause a lot of duplicate code that is difficult to maintain.
783
+
784
+ #### Localization with JSON Resource
785
+
786
+ Pages are localized by adding placeholders in the HTML files and providing a JSON resource that contains the translations to fill into the placeholders.
787
+
788
+ **Example Directory Structure:**
789
+
790
+ ```js
791
+ root/
792
+ ├── public/ // pages base path
793
+ │ ├── example.html // the page containing placeholders
794
+ ├── private/ // folder outside of public scope
795
+ │ └── translations.json // JSON resource file
796
+ ```
797
+
798
+ The JSON resource file loosely follows the [i18next](https://github.com/i18next/i18next) syntax, which is a syntax that is often supported by translation platforms, making it easy to manage translations, exporting them for use in Parse Server, and even to automate this workflow.
799
+
800
+ **Example JSON Content:**
801
+
802
+ ```json
803
+ {
804
+ "en": { // resource for language `en` (English)
805
+ "translation": {
806
+ "greeting": "Hello!"
807
+ }
808
+ },
809
+ "de": { // resource for language `de` (German)
810
+ "translation": {
811
+ "greeting": "Hallo!"
812
+ }
813
+ }
814
+ "de-AT": { // resource for locale `de-AT` (Austrian German)
815
+ "translation": {
816
+ "greeting": "Servus!"
817
+ }
818
+ }
819
+ }
820
+ ```
821
+
822
+ **Configuration Example:**
823
+
824
+ ```js
825
+ const api = new ParseServer({
826
+ ...otherOptions,
827
+
828
+ pages: {
829
+ enableLocalization: true,
830
+ localizationJsonPath: './private/localization.json',
831
+ localizationFallbackLocale: 'en'
832
+ }
833
+ }
834
+ ```
835
+
836
+ Pros:
837
+
838
+ - There is only one HTML file to maintain that contains the placeholders that are filled with the translations according to the locale.
839
+
840
+ Cons:
841
+
842
+ - Files cannot be easily previewed by viewing the file in a browser because the content contains only placeholders and even HTML or CSS changes may be dynamically applied, e.g. when a localization requires a Right-To-Left layout direction.
843
+ - Style and other fundamental layout changes may be more difficult to apply.
844
+
845
+ #### Dynamic placeholders
846
+
847
+ In addition to feature related default parameters such as `appId` and the translations provided via JSON resource, it is possible to define custom dynamic placeholders as part of the router configuration. This works independently of localization and, also if `enableLocalization` is disabled.
848
+
849
+ **Configuration Example:**
850
+
851
+ ```js
852
+ const api = new ParseServer({
853
+ ...otherOptions,
854
+
855
+ pages: {
856
+ placeholders: {
857
+ exampleKey: 'exampleValue'
858
+ }
859
+ }
860
+ }
861
+ ```
862
+
863
+ The placeholders can also be provided as function or as async function, with the `locale` and other feature related parameters passed through, to allow for dynamic placeholder values:
864
+
865
+ ```js
866
+ const api = new ParseServer({
867
+ ...otherOptions,
868
+
869
+ pages: {
870
+ placeholders: async (params) => {
871
+ const value = await doSomething(params.locale);
872
+ return {
873
+ exampleKey: value
874
+ };
875
+ }
876
+ }
877
+ }
878
+ ```
879
+
880
+ #### Reserved Keys
881
+
882
+ The following parameter and placeholder keys are reserved because they are used related to features such as password reset or email verification. They should not be used as translation keys in the JSON resource or as manually defined placeholder keys in the configuration: `appId`, `appName`, `email`, `error`, `locale`, `publicServerUrl`, `token`, `username`.
883
+
884
+ #### Parameters
885
+
886
+ | Parameter | Optional | Type | Default value | Example values | Environment variable | Description |
887
+ | ----------------------------------------------- | -------- | ------------------------------------- | -------------------------------------- | ---------------------------------------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
888
+ | `pages` | yes | `Object` | `undefined` | - | `PARSE_SERVER_PAGES` | The options for pages such as password reset and email verification. |
889
+ | `pages.enableLocalization` | yes | `Boolean` | `false` | - | `PARSE_SERVER_PAGES_ENABLE_LOCALIZATION` | Is true if pages should be localized; this has no effect on custom page redirects. |
890
+ | `pages.localizationJsonPath` | yes | `String` | `undefined` | `./private/translations.json` | `PARSE_SERVER_PAGES_LOCALIZATION_JSON_PATH` | The path to the JSON file for localization; the translations will be used to fill template placeholders according to the locale. |
891
+ | `pages.localizationFallbackLocale` | yes | `String` | `en` | `en`, `en-GB`, `default` | `PARSE_SERVER_PAGES_LOCALIZATION_FALLBACK_LOCALE` | The fallback locale for localization if no matching translation is provided for the given locale. This is only relevant when providing translation resources via JSON file. |
892
+ | `pages.placeholders` | yes | `Object`, `Function`, `AsyncFunction` | `undefined` | `{ exampleKey: 'exampleValue' }` | `PARSE_SERVER_PAGES_PLACEHOLDERS` | The placeholder keys and values which will be filled in pages; this can be a simple object or a callback function. |
893
+ | `pages.forceRedirect` | yes | `Boolean` | `false` | - | `PARSE_SERVER_PAGES_FORCE_REDIRECT` | Is `true` if responses should always be redirects and never content, `false` if the response type should depend on the request type (`GET` request -> content response; `POST` request -> redirect response). |
894
+ | `pages.pagesPath` | yes | `String` | `./public` | `./files/pages`, `../../pages` | `PARSE_SERVER_PAGES_PAGES_PATH` | The path to the pages directory; this also defines where the static endpoint `/apps` points to. |
895
+ | `pages.pagesEndpoint` | yes | `String` | `apps` | - | `PARSE_SERVER_PAGES_PAGES_ENDPOINT` | The API endpoint for the pages. |
896
+ | `pages.customUrls` | yes | `Object` | `{}` | `{ passwordReset: 'https://example.com/page.html' }` | `PARSE_SERVER_PAGES_CUSTOM_URLS` | The URLs to the custom pages |
897
+ | `pages.customUrls.passwordReset` | yes | `String` | `password_reset.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_PASSWORD_RESET` | The URL to the custom page for password reset. |
898
+ | `pages.customUrls.passwordResetSuccess` | yes | `String` | `password_reset_success.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_PASSWORD_RESET_SUCCESS` | The URL to the custom page for password reset -> success. |
899
+ | `pages.customUrls.passwordResetLinkInvalid` | yes | `String` | `password_reset_link_invalid.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_PASSWORD_RESET_LINK_INVALID` | The URL to the custom page for password reset -> link invalid. |
900
+ | `pages.customUrls.emailVerificationSuccess` | yes | `String` | `email_verification_success.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_EMAIL_VERIFICATION_SUCCESS` | The URL to the custom page for email verification -> success. |
901
+ | `pages.customUrls.emailVerificationSendFail` | yes | `String` | `email_verification_send_fail.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_EMAIL_VERIFICATION_SEND_FAIL` | The URL to the custom page for email verification -> link send fail. |
902
+ | `pages.customUrls.emailVerificationSendSuccess` | yes | `String` | `email_verification_send_success.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_EMAIL_VERIFICATION_SEND_SUCCESS` | The URL to the custom page for email verification -> resend link -> success. |
903
+ | `pages.customUrls.emailVerificationLinkInvalid` | yes | `String` | `email_verification_link_invalid.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_EMAIL_VERIFICATION_LINK_INVALID` | The URL to the custom page for email verification -> link invalid. |
904
+ | `pages.customUrls.emailVerificationLinkExpired` | yes | `String` | `email_verification_link_expired.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_EMAIL_VERIFICATION_LINK_EXPIRED` | The URL to the custom page for email verification -> link expired. |
905
+
906
+ ### Notes <!-- omit in toc -->
907
+
908
+ - In combination with the [Parse Server API Mail Adapter](https://www.npmjs.com/package/parse-server-api-mail-adapter) Parse Server provides a fully localized flow (emails -> pages) for the user. The email adapter sends a localized email and adds a locale parameter to the password reset or email verification link, which is then used to respond with localized pages.
909
+
910
+ ## Multi-Tenancy
911
+
912
+ Parse Server does not support multi-tenancy. Only one Parse Server instance may be mounted per Express app. Among other considerations, there is no isolation between apps in the same process. For example, Cloud Code runs in the same Node.js process as Parse Server and has full access to the server environment, such as server configuration, modules, and environment variables.
913
+
914
+ ## Logging
915
+
916
+ Parse Server will, by default, log:
917
+
918
+ - to the console
919
+ - daily rotating files as new line delimited JSON
920
+
921
+ Logs are also viewable in Parse Dashboard.
922
+
923
+ **Want to log each request and response?** Set the `VERBOSE` environment variable when starting `parse-server`. Usage :- `VERBOSE='1' parse-server --appId APPLICATION_ID --masterKey MASTER_KEY`
924
+
925
+ **Want logs to be placed in a different folder?** Pass the `PARSE_SERVER_LOGS_FOLDER` environment variable when starting `parse-server`. Usage :- `PARSE_SERVER_LOGS_FOLDER='<path-to-logs-folder>' parse-server --appId APPLICATION_ID --masterKey MASTER_KEY`
926
+
927
+ **Want to log specific levels?** Pass the `logLevel` parameter when starting `parse-server`. Usage :- `parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --logLevel LOG_LEVEL`
928
+
929
+ **Want new line delimited JSON error logs (for consumption by CloudWatch, Google Cloud Logging, etc)?** Pass the `JSON_LOGS` environment variable when starting `parse-server`. Usage :- `JSON_LOGS='1' parse-server --appId APPLICATION_ID --masterKey MASTER_KEY`
930
+
931
+ # Deprecations
932
+
933
+ See the [Deprecation Plan](https://github.com/parse-community/parse-server/blob/master/DEPRECATIONS.md) for an overview of deprecations and planned breaking changes.
934
+
935
+ # Live Query
936
+
937
+ Live queries are meant to be used in real-time reactive applications, where just using the traditional query paradigm could cause several problems, like increased response time and high network and server usage. Live queries should be used in cases where you need to continuously update a page with fresh data coming from the database, which often happens in (but is not limited to) online games, messaging clients and shared to-do lists.
938
+
939
+ Take a look at [Live Query Guide](https://docs.parseplatform.org/parse-server/guide/#live-queries), [Live Query Server Setup Guide](https://docs.parseplatform.org/parse-server/guide/#scalability) and [Live Query Protocol Specification](https://github.com/parse-community/parse-server/wiki/Parse-LiveQuery-Protocol-Specification). You can setup a standalone server or multiple instances for scalability (recommended).
940
+
941
+ # GraphQL
942
+
943
+ [GraphQL](https://graphql.org/), developed by Facebook, is an open-source data query and manipulation language for APIs. In addition to the traditional REST API, Parse Server automatically generates a GraphQL API based on your current application schema. Parse Server also allows you to define your custom GraphQL queries and mutations, whose resolvers can be bound to your cloud code functions.
944
+
945
+ ## Running
946
+
947
+ ### Using the CLI
948
+
949
+ The easiest way to run the Parse GraphQL API is through the CLI:
950
+
951
+ ```bash
952
+ $ npm install -g parse-server mongodb-runner
953
+ $ mongodb-runner start
954
+ $ parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --databaseURI mongodb://localhost/test --publicServerURL http://localhost:1337/parse --mountGraphQL --mountPlayground
955
+ ```
956
+
957
+ After starting the server, you can visit http://localhost:1337/playground in your browser to start playing with your GraphQL API.
958
+
959
+ **_Note:_** Do **_NOT_** use --mountPlayground option in production. The GraphQL Playground exposes the master key in the browser page. [Parse Dashboard](https://github.com/parse-community/parse-dashboard) has a built-in GraphQL Playground and is the recommended option for production apps.
960
+
961
+ ### Using Docker
962
+
963
+ You can also run the Parse GraphQL API inside a Docker container:
964
+
965
+ ```bash
966
+ $ git clone https://github.com/parse-community/parse-server
967
+ $ cd parse-server
968
+ $ docker build --tag parse-server .
969
+ $ docker run --name my-mongo -d mongo
970
+ ```
971
+
972
+ #### Running the Parse Server Image <!-- omit in toc -->
973
+
974
+ ```bash
975
+ $ docker run --name my-parse-server --link my-mongo:mongo -v config-vol:/parse-server/config -p 1337:1337 -d parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --databaseURI mongodb://mongo/test --publicServerURL http://localhost:1337/parse --mountGraphQL --mountPlayground
976
+ ```
977
+
978
+ **_Note:_** _If you want to use [Cloud Code](https://docs.parseplatform.org/cloudcode/guide/), add `-v cloud-code-vol:/parse-server/cloud --cloud /parse-server/cloud/main.js` to the command above. Make sure `main.js` is in the `cloud-code-vol` directory before starting Parse Server._
979
+
980
+ After starting the server, you can visit http://localhost:1337/playground in your browser to start playing with your GraphQL API.
981
+
982
+ **_Note:_** Do **_NOT_** use --mountPlayground option in production. The GraphQL Playground exposes the master key in the browser page. [Parse Dashboard](https://github.com/parse-community/parse-dashboard) has a built-in GraphQL Playground and is the recommended option for production apps.
983
+
984
+ ### Using Express.js
985
+
986
+ You can also mount the GraphQL API in an Express.js application together with the REST API or solo. You first need to create a new project and install the required dependencies:
987
+
988
+ ```bash
989
+ $ mkdir my-app
990
+ $ cd my-app
991
+ $ npm install parse-server express --save
992
+ ```
993
+
994
+ Then, create an `index.js` file with the following content:
995
+
996
+ ```js
997
+ const express = require('express');
998
+ const { ParseServer, ParseGraphQLServer } = require('parse-server');
999
+
1000
+ const app = express();
1001
+
1002
+ const parseServer = new ParseServer({
1003
+ databaseURI: 'mongodb://localhost:27017/test',
1004
+ appId: 'APPLICATION_ID',
1005
+ masterKey: 'MASTER_KEY',
1006
+ serverURL: 'http://localhost:1337/parse',
1007
+ publicServerURL: 'http://localhost:1337/parse',
1008
+ });
1009
+
1010
+ const parseGraphQLServer = new ParseGraphQLServer(parseServer, {
1011
+ graphQLPath: '/graphql',
1012
+ playgroundPath: '/playground',
1013
+ });
1014
+
1015
+ app.use('/parse', parseServer.app); // (Optional) Mounts the REST API
1016
+ parseGraphQLServer.applyGraphQL(app); // Mounts the GraphQL API
1017
+ parseGraphQLServer.applyPlayground(app); // (Optional) Mounts the GraphQL Playground - do NOT use in Production
1018
+
1019
+ await parseServer.start();
1020
+ app.listen(1337, function () {
1021
+ console.log('REST API running on http://localhost:1337/parse');
1022
+ console.log('GraphQL API running on http://localhost:1337/graphql');
1023
+ console.log('GraphQL Playground running on http://localhost:1337/playground');
1024
+ });
1025
+ ```
1026
+
1027
+ And finally start your app:
1028
+
1029
+ ```bash
1030
+ $ npx mongodb-runner start
1031
+ $ node index.js
1032
+ ```
1033
+
1034
+ After starting the app, you can visit http://localhost:1337/playground in your browser to start playing with your GraphQL API.
1035
+
1036
+ **_Note:_** Do **_NOT_** mount the GraphQL Playground in production. The GraphQL Playground exposes the master key in the browser page. [Parse Dashboard](https://github.com/parse-community/parse-dashboard) has a built-in GraphQL Playground and is the recommended option for production apps.
1037
+
1038
+ ## Checking the API health
1039
+
1040
+ Run the following:
1041
+
1042
+ ```graphql
1043
+ query Health {
1044
+ health
1045
+ }
1046
+ ```
1047
+
1048
+ You should receive the following response:
1049
+
1050
+ ```json
1051
+ {
1052
+ "data": {
1053
+ "health": true
1054
+ }
1055
+ }
1056
+ ```
1057
+
1058
+ ## Creating your first class
1059
+
1060
+ Since your application does not have any schema yet, you can use the `createClass` mutation to create your first class. Run the following:
1061
+
1062
+ ```graphql
1063
+ mutation CreateClass {
1064
+ createClass(
1065
+ name: "GameScore"
1066
+ schemaFields: {
1067
+ addStrings: [{ name: "playerName" }]
1068
+ addNumbers: [{ name: "score" }]
1069
+ addBooleans: [{ name: "cheatMode" }]
1070
+ }
1071
+ ) {
1072
+ name
1073
+ schemaFields {
1074
+ name
1075
+ __typename
1076
+ }
1077
+ }
1078
+ }
1079
+ ```
1080
+
1081
+ You should receive the following response:
1082
+
1083
+ ```json
1084
+ {
1085
+ "data": {
1086
+ "createClass": {
1087
+ "name": "GameScore",
1088
+ "schemaFields": [
1089
+ {
1090
+ "name": "objectId",
1091
+ "__typename": "SchemaStringField"
1092
+ },
1093
+ {
1094
+ "name": "updatedAt",
1095
+ "__typename": "SchemaDateField"
1096
+ },
1097
+ {
1098
+ "name": "createdAt",
1099
+ "__typename": "SchemaDateField"
1100
+ },
1101
+ {
1102
+ "name": "playerName",
1103
+ "__typename": "SchemaStringField"
1104
+ },
1105
+ {
1106
+ "name": "score",
1107
+ "__typename": "SchemaNumberField"
1108
+ },
1109
+ {
1110
+ "name": "cheatMode",
1111
+ "__typename": "SchemaBooleanField"
1112
+ },
1113
+ {
1114
+ "name": "ACL",
1115
+ "__typename": "SchemaACLField"
1116
+ }
1117
+ ]
1118
+ }
1119
+ }
1120
+ }
1121
+ ```
1122
+
1123
+ ## Using automatically generated operations
1124
+
1125
+ Parse Server learned from the first class that you created and now you have the `GameScore` class in your schema. You can now start using the automatically generated operations!
1126
+
1127
+ Run the following to create your first object:
1128
+
1129
+ ```graphql
1130
+ mutation CreateGameScore {
1131
+ createGameScore(fields: { playerName: "Sean Plott", score: 1337, cheatMode: false }) {
1132
+ id
1133
+ updatedAt
1134
+ createdAt
1135
+ playerName
1136
+ score
1137
+ cheatMode
1138
+ ACL
1139
+ }
1140
+ }
1141
+ ```
1142
+
1143
+ You should receive a response similar to this:
1144
+
1145
+ ```json
1146
+ {
1147
+ "data": {
1148
+ "createGameScore": {
1149
+ "id": "XN75D94OBD",
1150
+ "updatedAt": "2019-09-17T06:50:26.357Z",
1151
+ "createdAt": "2019-09-17T06:50:26.357Z",
1152
+ "playerName": "Sean Plott",
1153
+ "score": 1337,
1154
+ "cheatMode": false,
1155
+ "ACL": null
1156
+ }
1157
+ }
1158
+ }
1159
+ ```
1160
+
1161
+ You can also run a query to this new class:
1162
+
1163
+ ```graphql
1164
+ query GameScores {
1165
+ gameScores {
1166
+ results {
1167
+ id
1168
+ updatedAt
1169
+ createdAt
1170
+ playerName
1171
+ score
1172
+ cheatMode
1173
+ ACL
1174
+ }
1175
+ }
1176
+ }
1177
+ ```
1178
+
1179
+ You should receive a response similar to this:
1180
+
1181
+ ```json
1182
+ {
1183
+ "data": {
1184
+ "gameScores": {
1185
+ "results": [
1186
+ {
1187
+ "id": "XN75D94OBD",
1188
+ "updatedAt": "2019-09-17T06:50:26.357Z",
1189
+ "createdAt": "2019-09-17T06:50:26.357Z",
1190
+ "playerName": "Sean Plott",
1191
+ "score": 1337,
1192
+ "cheatMode": false,
1193
+ "ACL": null
1194
+ }
1195
+ ]
1196
+ }
1197
+ }
1198
+ }
1199
+ ```
1200
+
1201
+ ## Customizing your GraphQL Schema
1202
+
1203
+ Parse GraphQL Server allows you to create a custom GraphQL schema with own queries and mutations to be merged with the auto-generated ones. You can resolve these operations using your regular cloud code functions.
1204
+
1205
+ To start creating your custom schema, you need to code a `schema.graphql` file and initialize Parse Server with `--graphQLSchema` and `--cloud` options:
1206
+
1207
+ ```bash
1208
+ $ parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --databaseURI mongodb://localhost/test --publicServerURL http://localhost:1337/parse --cloud ./cloud/main.js --graphQLSchema ./cloud/schema.graphql --mountGraphQL --mountPlayground
1209
+ ```
1210
+
1211
+ ### Creating your first custom query <!-- omit in toc -->
1212
+
1213
+ Use the code below for your `schema.graphql` and `main.js` files. Then restart your Parse Server.
1214
+
1215
+ ```graphql
1216
+ # schema.graphql
1217
+ extend type Query {
1218
+ hello: String! @resolve
1219
+ }
1220
+ ```
1221
+
1222
+ ```js
1223
+ // main.js
1224
+ Parse.Cloud.define('hello', async () => {
1225
+ return 'Hello world!';
1226
+ });
1227
+ ```
1228
+
1229
+ You can now run your custom query using GraphQL Playground:
1230
+
1231
+ ```graphql
1232
+ query {
1233
+ hello
1234
+ }
1235
+ ```
1236
+
1237
+ You should receive the response below:
1238
+
1239
+ ```json
1240
+ {
1241
+ "data": {
1242
+ "hello": "Hello world!"
1243
+ }
1244
+ }
1245
+ ```
1246
+
1247
+ ## Learning more
1248
+
1249
+ The [Parse GraphQL Guide](http://docs.parseplatform.org/graphql/guide/) is a very good source for learning how to use the Parse GraphQL API.
1250
+
1251
+ You also have a very powerful tool inside your GraphQL Playground. Please look at the right side of your GraphQL Playground. You will see the `DOCS` and `SCHEMA` menus. They are automatically generated by analyzing your application schema. Please refer to them and learn more about everything that you can do with your Parse GraphQL API.
1252
+
1253
+ Additionally, the [GraphQL Learn Section](https://graphql.org/learn/) is a very good source to learn more about the power of the GraphQL language.
1254
+
1255
+ # Contributing
1256
+
1257
+ Please see the [Contributing Guide](CONTRIBUTING.md).
1258
+
1259
+ # Contributors
1260
+
1261
+ This project exists thanks to all the people who contribute... we'd love to see your face on this list!
1262
+
1263
+ <a href="../../graphs/contributors"><img src="https://opencollective.com/parse-server/contributors.svg?width=890&button=false" /></a>
1264
+
1265
+ # Sponsors
1266
+
1267
+ Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor!](https://opencollective.com/parse-server#sponsor)
1268
+
1269
+ <a href="https://opencollective.com/parse-server/sponsor/0/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/0/avatar.svg"></a>
1270
+ <a href="https://opencollective.com/parse-server/sponsor/1/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/1/avatar.svg"></a>
1271
+ <a href="https://opencollective.com/parse-server/sponsor/2/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/2/avatar.svg"></a>
1272
+ <a href="https://opencollective.com/parse-server/sponsor/3/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/3/avatar.svg"></a>
1273
+ <a href="https://opencollective.com/parse-server/sponsor/4/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/4/avatar.svg"></a>
1274
+ <a href="https://opencollective.com/parse-server/sponsor/5/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/5/avatar.svg"></a>
1275
+ <a href="https://opencollective.com/parse-server/sponsor/6/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/6/avatar.svg"></a>
1276
+ <a href="https://opencollective.com/parse-server/sponsor/7/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/7/avatar.svg"></a>
1277
+ <a href="https://opencollective.com/parse-server/sponsor/8/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/8/avatar.svg"></a>
1278
+ <a href="https://opencollective.com/parse-server/sponsor/9/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/9/avatar.svg"></a>
1279
+ <a href="https://opencollective.com/parse-server/sponsor/10/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/10/avatar.svg"></a>
1280
+ <a href="https://opencollective.com/parse-server/sponsor/11/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/11/avatar.svg"></a>
1281
+ <a href="https://opencollective.com/parse-server/sponsor/12/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/12/avatar.svg"></a>
1282
+ <a href="https://opencollective.com/parse-server/sponsor/13/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/13/avatar.svg"></a>
1283
+ <a href="https://opencollective.com/parse-server/sponsor/14/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/14/avatar.svg"></a>
1284
+ <a href="https://opencollective.com/parse-server/sponsor/15/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/15/avatar.svg"></a>
1285
+ <a href="https://opencollective.com/parse-server/sponsor/16/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/16/avatar.svg"></a>
1286
+ <a href="https://opencollective.com/parse-server/sponsor/17/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/17/avatar.svg"></a>
1287
+ <a href="https://opencollective.com/parse-server/sponsor/18/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/18/avatar.svg"></a>
1288
+ <a href="https://opencollective.com/parse-server/sponsor/19/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/19/avatar.svg"></a>
1289
+ <a href="https://opencollective.com/parse-server/sponsor/20/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/20/avatar.svg"></a>
1290
+ <a href="https://opencollective.com/parse-server/sponsor/21/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/21/avatar.svg"></a>
1291
+ <a href="https://opencollective.com/parse-server/sponsor/22/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/22/avatar.svg"></a>
1292
+ <a href="https://opencollective.com/parse-server/sponsor/23/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/23/avatar.svg"></a>
1293
+ <a href="https://opencollective.com/parse-server/sponsor/24/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/24/avatar.svg"></a>
1294
+ <a href="https://opencollective.com/parse-server/sponsor/25/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/25/avatar.svg"></a>
1295
+ <a href="https://opencollective.com/parse-server/sponsor/26/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/26/avatar.svg"></a>
1296
+ <a href="https://opencollective.com/parse-server/sponsor/27/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/27/avatar.svg"></a>
1297
+ <a href="https://opencollective.com/parse-server/sponsor/28/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/28/avatar.svg"></a>
1298
+ <a href="https://opencollective.com/parse-server/sponsor/29/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/29/avatar.svg"></a>
1299
+
1300
+ # Backers
1301
+
1302
+ Support us with a monthly donation and help us continue our activities. [Become a backer!](https://opencollective.com/parse-server#backer)
1303
+
1304
+ <a href="https://opencollective.com/parse-server#backers" target="_blank"><img src="https://opencollective.com/parse-server/backers.svg?width=890" /></a>
1305
+
1306
+ [open-collective-link]: https://opencollective.com/parse-server
1307
+ [log_release]: https://github.com/parse-community/parse-server/blob/release/changelogs/CHANGELOG_release.md
1308
+ [log_beta]: https://github.com/parse-community/parse-server/blob/beta/changelogs/CHANGELOG_beta.md
1309
+ [log_alpha]: https://github.com/parse-community/parse-server/blob/alpha/changelogs/CHANGELOG_alpha.md
1310
+
1311
+ [server-options] http://parseplatform.org/parse-server/api/release/ParseServerOptions.html