import { Callout } from "nextra/components"

# Creating a database adapter

Auth.js adapters allow you to integrate with any (even multiple) database/back-end service, even if we don't have an [official package](https://github.com/nextauthjs/next-auth/tree/main/packages) available yet. (We welcome PRs for new adapters! See the [guidelines](#official-adapter-guidelines) below.)

Auth.js adapters are very flexible, and you can implement only the methods you need, and only create the database tables/columns that are actually going to be used.

An Auth.js adapter is a function that receives an ORM/database client and returns an object with methods (based on the [`Adapter` interface](/reference/core/adapters#adapter)) that interact with the database. The same database Adapter will be compatible with any Auth.js library.

Optionally, you can run our [Adapter tests](https://github.com/nextauthjs/next-auth/blob/main/packages/utils/adapter.ts) on your adapter to ensure it is compliant with the Auth.js.

## User management

Auth.js differentiates between users and accounts. A user can have multiple accounts. An account is created for each provider type the user signs in with for the first time. For example, if a user signs in with Google and then with Facebook, they will have two accounts, one for each provider. The first provider the user signs in with will also be used to create the user object. See the [`profile()` provider method](/reference/core/providers#profile).

### Methods and models

<div style={{display: "grid", gridTemplateColumns: "1fr 1fr"}}>
  <span>
    - [`createUser`](/reference/core/adapters#createuser)
    - [`getUser`](/reference/core/adapters#getuser)
    - [`getUserByAccount`](/reference/core/adapters#getuserbyaccount)
    - [`updateUser`](/reference/core/adapters#updateuser)
    - [`linkAccount`](/reference/core/adapters#linkaccount)

    Not yet invoked by Auth.js:
    - [_`deleteUser`_](/reference/core/adapters#deleteuser)
    - [_`unlinkAccount`_](/reference/core/adapters#unlinkaccount)

  </span>
  ```mermaid
  erDiagram
      User ||--|{ Account : ""
      User {
        string id
      }
      Account {
        string userId
        string type
        string provider
        string providerAccountId
      }
  ```
</div>

See also: [User](/concepts/database-models#user) and [Account](/concepts/database-models#account) models.

<Callout type="info">
  Although Auth.js doesn't require it, for basic display purposes, we recommend
  adding the following columns to the `User` table as well: `name`, `email`,
  `image`. You can configure the columns via the [`profile()` provider
  method](/reference/core/providers#profile). If you don't need to save these
  properties, create an empty `profile() {}` method.
</Callout>

<Callout type="info">
  Although Auth.js doesn't require it, the `Account` table typically saves
  tokens retrieved from the provider. You can configure the columns via the
  [`account()` provider method](/reference/core/providers#account). If you don't
  need to save tokens, create an empty `account() {}` method.
</Callout>

## Database session management

Auth.js can manage sessions in two ways. Learn about them and their advantages and disadvantages at [Concepts: Session strategies](/concepts/session-strategies).

### Methods and models

<div style={{display: "grid", gridTemplateColumns: "1fr 1fr"}}>
  <span>
    - [`createSession`](/reference/core/adapters#createsession)
    - [`getSessionAndUser`](/reference/core/adapters#getsessionanduser)
    - [`updateSession`](/reference/core/adapters#updatesession)
    - [`deleteSession`](/reference/core/adapters#deletesession)
  </span>
  ```mermaid
  erDiagram
      User ||--|{ Account : ""
      User {
        string id
      }
      User ||--|{ Session : ""
      Session {
        string id
        timestamp expires
        string sessionToken
        string userId
      }
      Account {
        string userId
        string type
        string provider
        string providerAccountId
      }
  ```
</div>

If you want to use database sessions, you will need to implement the following methods:

To add database session management, you will need to expand your database tables/columns as follows:

See also: [Session](/concepts/database-models#session) models.

## Verification tokens

When you want to support email/passwordless login, Auth.js uses a database to store temporary verification tokens that are tied to a user's email address.

### Methods and models

<div style={{display: "grid", gridTemplateColumns: "1fr 1fr"}}>
  <span>
    - [`getUserByEmail`](/reference/core/adapters#getuserbyemail)
    - [`createVerificationToken`](/reference/core/adapters#createverificationtoken)
    - [`useVerificationToken`](/reference/core/adapters#useverificationtoken)
  </span>
  ```mermaid
  erDiagram
      User ||--|{ Account : ""
      User {
        string id
        timestamp emailVerified
      }
      Account {
        string userId
        string type
        string provider
        string providerAccountId
      }
      User ||--|{ VerificationToken : ""
      VerificationToken {
        string identifier
        string token
        timestamp expires
      }
  ```
</div>

See also: [Verification Token](/concepts/database-models#verification-token) models.

## Official adapter guidelines

<Callout type="info">
  When all of the below steps are done, you are ready to submit a PR to our
  [repository](https://github.com/nextauthjs/next-auth).
</Callout>

If you created an adapter and want us to distribute it as an official package, please make sure it meets the following requirements. Check out this [existing adapter](https://github.com/nextauthjs/next-auth/tree/main/packages/adapter-prisma) to learn about the package structure, required files, test setup, config, etc.

1. The Adapter _must_ implement all methods of the [`Adapter` interface](/reference/core/adapters#adapter)
1. [Adapter tests](https://github.com/nextauthjs/next-auth/blob/main/packages/utils/adapter.ts) _must_ be included and _must_ pass. Docker is favored over services, to make CI resilient to network errors and to reduce the number of GitHub Action Secrets (which also lets us run these tests in fork PRs)
1. The Adapter _must_ follow these coding styles

   - Written in TypeScript
   - Passes the linting rules of the monorepo
   - Does not include polyfills
   - Configured as an ES module (ESM)
   - Documented via JSDoc comments
   - Have at least one named export exported from its main module. (For example `export function MyAdapter(): Adapter {}`)
   - collection/table names should follow the convention (plural/singular, camelCase/snake_case) of the underlying ORM/database docs/conventions

1. Configure the monorepo to help us maintain the package

   - Add a (preferably `.svg`) logo to [this directory](https://github.com/nextauthjs/next-auth/tree/main/docs/public/img/adapters)
   - Add the Adapter to our GitHub workflow files [here](https://github.com/nextauthjs/next-auth/tree/main/.github/workflows/release.yml#L12) and [here](https://github.com/nextauthjs/next-auth/tree/main/.github/pr-labeler.yml)
   - Make sure to [`.gitignore` generated files](https://github.com/nextauthjs/next-auth/tree/main/.gitignore#L58) if there are any

1. The Adapter _must_ be able to handle any property coming from the user

   ORMs/database clients might have their own data types, but Auth.js expects these to be normalized as plain JavaScript objects for consistency. If your ORM/database client does not convert automatically, you need to convert the values when reading/writing from/to the database.

   You might be tempted to check the name of a property and convert it based on that, but this is not scalable (eg.: a `User` object might have more than one `Date` property, not only `emailVerified`).

   Instead, we recommend creating util functions that convert the values. Below is an example of how to convert dates (if your ORM/database client uses other data types, remember to convert them too, not only dates). It checks if the value can be parsed as a date, and if so, it converts it to a `Date` object. Otherwise, it leaves the original value as is.:

```ts
// https://github.com/honeinc/is-iso-date/blob/8831e79b5b5ee615920dcb350a355ffc5cbf7aed/index.js#L5
const isoDateRE =
  /(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/

const isDate = (val: any): val is ConstructorParameters<typeof Date>[0] =>
  !!(val && isoDateRE.test(val) && !isNaN(Date.parse(val)))

export const format = {
  /** Takes an object that's coming from a database and converts it to plain JavaScript. */
  from<T>(object: Record<string, any> = {}): T {
    const newObject: Record<string, unknown> = {}
    for (const [key, value] of Object.entries(object))
      if (isDate(value)) newObject[key] = new Date(value)
      else newObject[key] = value
    return newObject as T
  },
  /** Takes an object that's coming from Auth.js and prepares it to be written to the database. */
  to<T>(object: Record<string, any>): T {
    const newObject: Record<string, unknown> = {}
    for (const [key, value] of Object.entries(object))
      if (value instanceof Date) newObject[key] = value.toISOString()
      else newObject[key] = value
    return newObject as T
  },
}
```

## TypeScript

You can take advantage of the types that comes with the framework packages (i.e. `next-auth/adapters`, `@auth/sveltekit/adapters`).

```ts
import type { Adapter } from "next-auth/adapters"

function MyAdapter(): Adapter {
  return {
    // your adapter methods here
  }
}
```

When writing your Adapter in JavaScript, you can still use JSDoc to get helpful editor hints and auto-completion.

```js {1}
/** @return { import("next-auth/adapters").Adapter } */
function MyAdapter() {
  return {
    // your adapter methods here
  }
}
```

## Resources

- [Official adapters' source code](https://github.com/nextauthjs/next-auth/tree/main/packages)
- [`Adapter` interface](/reference/core/adapters#adapter)
