Skip to main content
The Shopify App JavaScript SDK provides official adapters for various database systems. Each adapter implements the SessionStorage interface and handles connection management, serialization, and migrations automatically.

PostgreSQL

Production-ready relational database adapter with automatic migrations.

Installation

npm install @shopify/shopify-app-session-storage-postgresql

Basic Setup

import {PostgreSQLSessionStorage} from '@shopify/shopify-app-session-storage-postgresql';

const sessionStorage = new PostgreSQLSessionStorage(
  'postgres://username:password@localhost/database'
);

Configuration Options

sessionTableName
string
default:"shopify_sessions"
Name of the table to store sessions.
port
number
default:"3211"
PostgreSQL server port.
migratorOptions
object
Migration configuration options.

Connection String Format

postgres://username:password@host:port/database
postgresql://username:password@host:port/database?ssl=true
The adapter automatically creates the sessions table and handles schema migrations.

MySQL

MySQL/MariaDB adapter with connection pooling support.

Installation

npm install @shopify/shopify-app-session-storage-mysql

Basic Setup

import {MySQLSessionStorage} from '@shopify/shopify-app-session-storage-mysql';

const sessionStorage = new MySQLSessionStorage(
  'mysql://username:password@localhost/database'
);

Configuration Options

sessionTableName
string
default:"shopify_sessions"
Name of the table to store sessions.
connectionPoolLimit
number
default:"10"
Maximum number of connections in the pool.

Connection String Format

mysql://username:password@host:port/database
mysql://username:password@host/database?connectionLimit=20

Redis

High-performance in-memory session storage with automatic key prefixing.

Installation

npm install @shopify/shopify-app-session-storage-redis

Basic Setup

import {RedisSessionStorage} from '@shopify/shopify-app-session-storage-redis';

const sessionStorage = new RedisSessionStorage(
  'redis://username:password@localhost:6379/0'
);

Configuration Options

sessionKeyPrefix
string
default:"shopify_sessions"
Prefix for all session keys in Redis.
migratorOptions
object
Migration configuration.
onError
function
Error handler callback.

Connection String Format

redis://username:password@host:port/db
redis://:password@host:port/db
rediss://host:port/db  # SSL/TLS connection
When passing a pre-configured Redis client, do not include additional options. Configure the client before passing it to the constructor.

MongoDB

Flexible document-based session storage.

Installation

npm install @shopify/shopify-app-session-storage-mongodb

Basic Setup

import {MongoDBSessionStorage} from '@shopify/shopify-app-session-storage-mongodb';

const sessionStorage = new MongoDBSessionStorage(
  new URL('mongodb://localhost:27017'),
  'myshopifyapp',  // database name
  {}
);

Configuration Options

sessionCollectionName
string
default:"shopify_sessions"
Name of the MongoDB collection to store sessions.

Connection String Format

mongodb://username:password@host:port/
mongodb://localhost:27017/
mongodb+srv://username:[email protected]/
The database name is specified as a separate parameter, not in the connection URL.

DynamoDB

AWS serverless database adapter for scalable session storage.

Installation

npm install @shopify/shopify-app-session-storage-dynamodb

Basic Setup

import {DynamoDBSessionStorage} from '@shopify/shopify-app-session-storage-dynamodb';

const sessionStorage = new DynamoDBSessionStorage({
  sessionTableName: 'shopify_sessions',
  shopIndexName: 'shop_index'
});

Configuration Options

sessionTableName
string
default:"shopify_sessions"
Name of the DynamoDB table.
shopIndexName
string
default:"shop_index"
Name of the Global Secondary Index on the shop attribute.
config
DynamoDBClientConfig
AWS SDK DynamoDB client configuration.

Required Table Setup

Create a DynamoDB table with:
  • Partition Key: id (String)
  • Global Secondary Index: shop_index
    • Partition Key: shop (String)
    • Projection: id and shop attributes
Resources:
  SessionsTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: shopify_sessions
      AttributeDefinitions:
        - AttributeName: id
          AttributeType: S
        - AttributeName: shop
          AttributeType: S
      KeySchema:
        - AttributeName: id
          KeyType: HASH
      GlobalSecondaryIndexes:
        - IndexName: shop_index
          KeySchema:
            - AttributeName: shop
              KeyType: HASH
          Projection:
            ProjectionType: INCLUDE
            NonKeyAttributes:
              - id
          ProvisionedThroughput:
            ReadCapacityUnits: 5
            WriteCapacityUnits: 5
      ProvisionedThroughput:
        ReadCapacityUnits: 5
        WriteCapacityUnits: 5

SQLite

Lightweight file-based database, ideal for development and small deployments.

Installation

npm install @shopify/shopify-app-session-storage-sqlite

Basic Setup

import {SQLiteSessionStorage} from '@shopify/shopify-app-session-storage-sqlite';

const sessionStorage = new SQLiteSessionStorage(
  '/path/to/database.sqlite'
);

Configuration Options

sessionTableName
string
default:"shopify_sessions"
Name of the table to store sessions.
SQLite is not recommended for production apps with multiple server instances. Use a networked database instead.

Drizzle ORM

Type-safe ORM adapters for PostgreSQL, MySQL, and SQLite.

Installation

npm install @shopify/shopify-app-session-storage-drizzle drizzle-orm
Install the appropriate database driver:
npm install pg

PostgreSQL Setup

import {DrizzleSessionStoragePostgres} from '@shopify/shopify-app-session-storage-drizzle';
import {drizzle} from 'drizzle-orm/node-postgres';
import {pgTable, text, boolean, bigint, timestamp} from 'drizzle-orm/pg-core';
import {Pool} from 'pg';

// Define your session table schema
const sessionTable = pgTable('session', {
  id: text('id').primaryKey(),
  shop: text('shop').notNull(),
  state: text('state').notNull(),
  isOnline: boolean('isOnline').default(false).notNull(),
  scope: text('scope'),
  expires: timestamp('expires', {mode: 'date'}),
  accessToken: text('accessToken').notNull(),
  userId: bigint('userId', {mode: 'number'}),
  firstName: text('firstName'),
  lastName: text('lastName'),
  email: text('email'),
  accountOwner: boolean('accountOwner'),
  locale: text('locale'),
  collaborator: boolean('collaborator'),
  emailVerified: boolean('emailVerified'),
  refreshToken: text('refreshToken'),
  refreshTokenExpires: timestamp('refreshTokenExpires', {mode: 'date'}),
});

// Create database connection
const pool = new Pool({
  connectionString: process.env.DATABASE_URL
});

const db = drizzle(pool);

// Create session storage
const sessionStorage = new DrizzleSessionStoragePostgres(db, sessionTable);

MySQL Setup

import {DrizzleSessionStorageMySQL} from '@shopify/shopify-app-session-storage-drizzle';
import {drizzle} from 'drizzle-orm/mysql2';
import {mysqlTable, text, boolean, bigint, timestamp} from 'drizzle-orm/mysql-core';
import mysql from 'mysql2/promise';

const sessionTable = mysqlTable('session', {
  id: text('id').primaryKey(),
  shop: text('shop').notNull(),
  state: text('state').notNull(),
  isOnline: boolean('isOnline').default(false).notNull(),
  scope: text('scope'),
  expires: timestamp('expires', {mode: 'date'}),
  accessToken: text('accessToken').notNull(),
  userId: bigint('userId', {mode: 'number'}),
  firstName: text('firstName'),
  lastName: text('lastName'),
  email: text('email'),
  accountOwner: boolean('accountOwner'),
  locale: text('locale'),
  collaborator: boolean('collaborator'),
  emailVerified: boolean('emailVerified'),
  refreshToken: text('refreshToken'),
  refreshTokenExpires: timestamp('refreshTokenExpires', {mode: 'date'}),
});

const connection = await mysql.createConnection(process.env.DATABASE_URL);
const db = drizzle(connection);
const sessionStorage = new DrizzleSessionStorageMySQL(db, sessionTable);

SQLite Setup

import {DrizzleSessionStorageSQLite} from '@shopify/shopify-app-session-storage-drizzle';
import {drizzle} from 'drizzle-orm/better-sqlite3';
import {sqliteTable, text, integer} from 'drizzle-orm/sqlite-core';
import Database from 'better-sqlite3';

const sessionTable = sqliteTable('session', {
  id: text('id').primaryKey(),
  shop: text('shop').notNull(),
  state: text('state').notNull(),
  isOnline: integer('isOnline', {mode: 'boolean'}).default(false).notNull(),
  scope: text('scope'),
  expires: integer('expires'),
  accessToken: text('accessToken').notNull(),
  userId: integer('userId'),
  firstName: text('firstName'),
  lastName: text('lastName'),
  email: text('email'),
  accountOwner: integer('accountOwner', {mode: 'boolean'}),
  locale: text('locale'),
  collaborator: integer('collaborator', {mode: 'boolean'}),
  emailVerified: integer('emailVerified', {mode: 'boolean'}),
  refreshToken: text('refreshToken'),
  refreshTokenExpires: integer('refreshTokenExpires'),
});

const sqlite = new Database('sessions.db');
const db = drizzle(sqlite);
const sessionStorage = new DrizzleSessionStorageSQLite(db, sessionTable);
You must run migrations manually when using Drizzle. The adapter does not auto-create tables.

Prisma ORM

Modern database toolkit with type-safety and migrations.

Installation

npm install @shopify/shopify-app-session-storage-prisma @prisma/client
npm install -D prisma

Setup

  1. Define your Prisma schema (prisma/schema.prisma):
model Session {
  id                   String    @id
  shop                 String
  state                String
  isOnline             Boolean   @default(false)
  scope                String?
  expires              DateTime?
  accessToken          String
  userId               BigInt?
  firstName            String?
  lastName             String?
  email                String?
  accountOwner         Boolean   @default(false)
  locale               String?
  collaborator         Boolean   @default(false)
  emailVerified        Boolean   @default(false)
  refreshToken         String?
  refreshTokenExpires  DateTime?
}
  1. Generate Prisma client:
npx prisma generate
npx prisma migrate dev --name init
  1. Create session storage:
import {PrismaSessionStorage} from '@shopify/shopify-app-session-storage-prisma';
import {PrismaClient} from '@prisma/client';

const prisma = new PrismaClient();

const sessionStorage = new PrismaSessionStorage(prisma, {
  tableName: 'session',  // Must match your model name
  connectionRetries: 2,
  connectionRetryIntervalMs: 5000
});

// Wait for storage to be ready
if (await sessionStorage.isReady()) {
  console.log('Session storage is ready');
}

Configuration Options

tableName
string
default:"session"
Name of the Prisma model to use (case-sensitive).
connectionRetries
number
default:"2"
Number of times to retry database connection.
connectionRetryIntervalMs
number
default:"5000"
Milliseconds to wait between connection retries.
The tableName option must exactly match your Prisma model name, including capitalization.

Cloudflare KV

Edge-compatible session storage for Cloudflare Workers.

Installation

npm install @shopify/shopify-app-session-storage-kv

Setup

import {KVSessionStorage} from '@shopify/shopify-app-session-storage-kv';

export default {
  async fetch(request: Request, env: Env) {
    const sessionStorage = new KVSessionStorage(env.SESSION_KV);
    
    // Use sessionStorage in your app
  }
}

wrangler.toml Configuration

name = "my-shopify-app"
main = "src/index.ts"
compatibility_date = "2024-01-01"

[[kv_namespaces]]
binding = "SESSION_KV"
id = "your-kv-namespace-id"
KV storage is eventually consistent. For most session use cases, this is acceptable.

Memory (Development Only)

In-memory session storage for development and testing.

Installation

npm install @shopify/shopify-app-session-storage-memory

Setup

import {MemorySessionStorage} from '@shopify/shopify-app-session-storage-memory';

const sessionStorage = new MemorySessionStorage();
DO NOT USE IN PRODUCTION
  • Sessions are lost when the process restarts
  • Not shared across multiple server instances
  • No persistence between deployments
  • Memory usage grows indefinitely

When to Use

  • Local development
  • Unit testing
  • Integration tests
  • Proof-of-concept apps

Comparison Table

AdapterBest ForAuto-MigrationsConnection PoolingServerless
PostgreSQLProduction appsYesYesNo
MySQLProduction appsYesYesNo
RedisHigh-traffic appsYesYesYes
MongoDBFlexible schemasNoYesYes
DynamoDBAWS serverlessNoN/AYes
SQLiteDevelopmentYesNoNo
DrizzleType-safe SQLNoDependsDepends
PrismaModern workflowsNoYesDepends
KVCloudflare WorkersNoN/AYes
MemoryDevelopment onlyN/AN/ANo

Next Steps

SessionStorage Interface

Learn about the core interface

Overview

Session storage concepts

Build docs developers (and LLMs) love