--- title: Local API label: Overview order: 10 desc: The Payload Local API allows you to interact with your database and execute the same operations that are available through REST and GraphQL within Node, directly on your server. keywords: local api, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs --- The Payload Local API gives you the ability to execute the same operations that are available through REST and GraphQL within Node, directly on your server. Here, you don't need to deal with server latency or network speed whatsoever and can interact directly with your database. Tip:
The Local API is incredibly powerful when used in React Server Components and other similar server-side contexts. With other headless CMS, you need to request your data from third-party servers via an HTTP layer, which can add significant loading time to your server-rendered pages. With Payload, you don't have to leave your server to gather the data you need. It can be incredibly fast and is definitely a game changer.
Here are some common examples of how you can use the Local API: - Fetching Payload data within React Server Components - Seeding data via Node seed scripts that you write and maintain - Opening custom Next.js route handlers which feature additional functionality but still rely on Payload - Within [Access Control](../access-control) and [Hooks](../hooks/overview) ## Accessing Payload You can gain access to the currently running `payload` object via two ways: #### Accessing from args or `req` In most places within Payload itself, you can access `payload` directly from the arguments of [Hooks](../hooks/overview), [Access Control](../access-control/overview), [Validation](../fields/overview#validations) functions, and similar. This is the simplest way to access Payload in most cases. Most config functions take the `req` (Request) object, which has Payload bound to it (`req.payload`). Example: ```ts const afterChangeHook: CollectionAfterChangeHook = async ({ req: { payload } }) => { const posts = await payload.find({ collection: 'posts', }) } ``` #### Importing it If you want to import Payload in places where you don't have the option to access it from function arguments or `req`, you can import it and initialize it. ```ts import { getPayload } from 'payload' import config from '@payload-config' const payload = await getPayload({ config }) ``` If you're working in Next.js' development mode, Payload will work with Hot Module Replacement (HMR), and as you make changes to your Payload Config, your usage of Payload will always be in sync with your changes. In production, `getPayload` simply disables all HMR functionality so you don't need to write your code any differently. We handle optimization for you in production mode. If you are accessing Payload via function arguments or `req.payload`, HMR is automatically supported if you are using it within Next.js. For more information about using Payload outside of Next.js, [click here](./outside-nextjs). ## Local options available You can specify more options within the Local API vs. REST or GraphQL due to the server-only context that they are executed in. | Local Option | Description | | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `collection` | Required for Collection operations. Specifies the Collection slug to operate against. | | `data` | The data to use within the operation. Required for `create`, `update`. | | `depth` | [Control auto-population](../queries/depth) of nested relationship and upload fields. | | `locale` | Specify [locale](/docs/configuration/localization) for any returned documents. | | `select` | Specify [select](../queries/select) to control which fields to include to the result. | | `populate` | Specify [populate](../queries/select#populate) to control which fields to include to the result from populated documents. | | `fallbackLocale` | Specify a [fallback locale](/docs/configuration/localization) to use for any returned documents. | | `overrideAccess` | Skip access control. By default, this property is set to true within all Local API operations. | | `overrideLock` | By default, document locks are ignored (`true`). Set to `false` to enforce locks and prevent operations when a document is locked by another user. [More details](../admin/locked-documents). | | `user` | If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks. | | `showHiddenFields` | Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config. | | `pagination` | Set to false to return all documents and avoid querying for document counts. | | `context` | [Context](/docs/hooks/context), which will then be passed to `context` and `req.context`, which can be read by hooks. Useful if you want to pass additional information to the hooks which shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook to determine if it should run or not. | | `disableErrors` | When set to `true`, errors will not be thrown. Instead, the `findByID` operation will return `null`, and the `find` operation will return an empty documents array. | | `disableTransaction` | When set to `true`, a [database transactions](../database/transactions) will not be initialized. | _There are more options available on an operation by operation basis outlined below._ ## Transactions When your database uses transactions you need to thread req through to all local operations. Postgres uses transactions and MongoDB uses transactions when you are using replica sets. Passing req without transactions is still recommended. ```js const post = await payload.find({ collection: 'posts', req, // passing req is recommended }) ``` Note:
By default, all access control checks are disabled in the Local API, but you can re-enable them if you'd like, as well as pass a specific user to run the operation with.
## Collections The following Collection operations are available through the Local API: ### Create#collection-create ```js // The created Post document is returned const post = await payload.create({ collection: 'posts', // required data: { // required title: 'sure', description: 'maybe', }, locale: 'en', fallbackLocale: false, user: dummyUserDoc, overrideAccess: true, showHiddenFields: false, // If creating verification-enabled auth doc, // you can optionally disable the email that is auto-sent disableVerificationEmail: true, // If your collection supports uploads, you can upload // a file directly through the Local API by providing // its full, absolute file path. filePath: path.resolve(__dirname, './path-to-image.jpg'), // Alternatively, you can directly pass a File, // if file is provided, filePath will be omitted file: uploadedFile, // If you want to create a document that is a duplicate of another document duplicateFromID: 'document-id-to-duplicate', }) ``` ### Find#collection-find ```js // Result will be a paginated set of Posts. // See /docs/queries/pagination for more. const result = await payload.find({ collection: 'posts', // required depth: 2, page: 1, limit: 10, pagination: false, // If you want to disable pagination count, etc. where: {}, // pass a `where` query here sort: '-title', locale: 'en', fallbackLocale: false, user: dummyUser, overrideAccess: false, showHiddenFields: true, }) ``` ### Find by ID#collection-find-by-id ```js // Result will be a Post document. const result = await payload.findByID({ collection: 'posts', // required id: '507f1f77bcf86cd799439011', // required depth: 2, locale: 'en', fallbackLocale: false, user: dummyUser, overrideAccess: false, showHiddenFields: true, }) ``` ### Count#collection-count ```js // Result will be an object with: // { // totalDocs: 10, // count of the documents satisfies query // } const result = await payload.count({ collection: 'posts', // required locale: 'en', where: {}, // pass a `where` query here user: dummyUser, overrideAccess: false, }) ``` ### Update by ID#collection-update-by-id ```js // Result will be the updated Post document. const result = await payload.update({ collection: 'posts', // required id: '507f1f77bcf86cd799439011', // required data: { // required title: 'sure', description: 'maybe', }, depth: 2, locale: 'en', fallbackLocale: false, user: dummyUser, overrideAccess: false, overrideLock: false, // By default, document locks are ignored. Set to false to enforce locks. showHiddenFields: true, // If your collection supports uploads, you can upload // a file directly through the Local API by providing // its full, absolute file path. filePath: path.resolve(__dirname, './path-to-image.jpg'), // If you are uploading a file and would like to replace // the existing file instead of generating a new filename, // you can set the following property to `true` overwriteExistingFiles: true, }) ``` ### Update Many#collection-update-many ```js // Result will be an object with: // { // docs: [], // each document that was updated // errors: [], // each error also includes the id of the document // } const result = await payload.update({ collection: 'posts', // required where: { // required fieldName: { equals: 'value' }, }, data: { // required title: 'sure', description: 'maybe', }, depth: 0, locale: 'en', fallbackLocale: false, user: dummyUser, overrideAccess: false, overrideLock: false, // By default, document locks are ignored. Set to false to enforce locks. showHiddenFields: true, // If your collection supports uploads, you can upload // a file directly through the Local API by providing // its full, absolute file path. filePath: path.resolve(__dirname, './path-to-image.jpg'), // If you are uploading a file and would like to replace // the existing file instead of generating a new filename, // you can set the following property to `true` overwriteExistingFiles: true, }) ``` ### Delete#collection-delete ```js // Result will be the now-deleted Post document. const result = await payload.delete({ collection: 'posts', // required id: '507f1f77bcf86cd799439011', // required depth: 2, locale: 'en', fallbackLocale: false, user: dummyUser, overrideAccess: false, overrideLock: false, // By default, document locks are ignored. Set to false to enforce locks. showHiddenFields: true, }) ``` ### Delete Many#collection-delete-many ```js // Result will be an object with: // { // docs: [], // each document that is now deleted // errors: [], // any errors that occurred, including the id of the errored on document // } const result = await payload.delete({ collection: 'posts', // required where: { // required fieldName: { equals: 'value' }, }, depth: 0, locale: 'en', fallbackLocale: false, user: dummyUser, overrideAccess: false, overrideLock: false, // By default, document locks are ignored. Set to false to enforce locks. showHiddenFields: true, }) ``` ## Auth Operations If a collection has [`Authentication`](/docs/authentication/overview) enabled, additional Local API operations will be available: ### Auth ```js // If you're using Next.js, you'll have to import headers from next/headers, like so: // import { headers as nextHeaders } from 'next/headers' // you'll also have to await headers inside your function, or component, like so: // const headers = await nextHeaders() // If you're using payload outside of Next.js, you'll have to provide headers accordingly. // result will be formatted as follows: // { // permissions: { ... }, // object containing current user's permissions // user: { ... }, // currently logged in user's document // responseHeaders: { ... } // returned headers from the response // } const result = await payload.auth({headers}) ``` ### Login ```js // result will be formatted as follows: // { // token: 'o38jf0q34jfij43f3f...', // JWT used for auth // user: { ... } // the user document that just logged in // exp: 1609619861 // the UNIX timestamp when the JWT will expire // } const result = await payload.login({ collection: 'users', // required data: { // required email: 'dev@payloadcms.com', password: 'rip', }, req: req, // pass a Request object to be provided to all hooks res: res, // used to automatically set an HTTP-only auth cookie depth: 2, locale: 'en', fallbackLocale: false, overrideAccess: false, showHiddenFields: true, }) ``` ### Forgot Password ```js // Returned token will allow for a password reset const token = await payload.forgotPassword({ collection: 'users', // required data: { // required email: 'dev@payloadcms.com', }, req: req, // pass a Request object to be provided to all hooks }) ``` ### Reset Password ```js // Result will be formatted as follows: // { // token: 'o38jf0q34jfij43f3f...', // JWT used for auth // user: { ... } // the user document that just logged in // } const result = await payload.resetPassword({ collection: 'users', // required data: { // required password: req.body.password, // the new password to set token: 'afh3o2jf2p3f...', // the token generated from the forgotPassword operation }, req: req, // pass a Request object to be provided to all hooks res: res, // used to automatically set an HTTP-only auth cookie }) ``` ### Unlock ```js // Returned result will be a boolean representing success or failure const result = await payload.unlock({ collection: 'users', // required data: { // required email: 'dev@payloadcms.com', }, req: req, // pass a Request object to be provided to all hooks overrideAccess: true, }) ``` ### Verify ```js // Returned result will be a boolean representing success or failure const result = await payload.verifyEmail({ collection: 'users', // required token: 'afh3o2jf2p3f...', // the token saved on the user as `_verificationToken` }) ``` ## Globals The following Global operations are available through the Local API: ### Find#global-find ```js // Result will be the Header Global. const result = await payload.findGlobal({ slug: 'header', // required depth: 2, locale: 'en', fallbackLocale: false, user: dummyUser, overrideAccess: false, showHiddenFields: true, }) ``` ### Update#global-update ```js // Result will be the updated Header Global. const result = await payload.updateGlobal({ slug: 'header', // required data: { // required nav: [ { url: 'https://google.com', }, { url: 'https://payloadcms.com', }, ], }, depth: 2, locale: 'en', fallbackLocale: false, user: dummyUser, overrideAccess: false, overrideLock: false, // By default, document locks are ignored. Set to false to enforce locks. showHiddenFields: true, }) ``` ## TypeScript Local API calls will automatically infer your [generated types](/docs/typescript/generating-types). Here is an example of usage: ```ts // Properly inferred as `Post` type const post = await payload.create({ collection: 'posts', // Data will now be typed as Post and give you type hints data: { title: 'my title', description: 'my description', }, }) ```