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
URL Connection
With Credentials
Custom Options
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.
Migration configuration options.
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
URL Connection
With Credentials
Connection Pool
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.
Maximum number of connections in the pool.
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
URL Connection
With Credentials
Redis Client
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.
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
URL Connection
With Credentials
Custom Collection
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.
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.
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
SQLite
Lightweight file-based database, ideal for development and small deployments.
Installation
npm install @shopify/shopify-app-session-storage-sqlite
Basic Setup
File Path
In-Memory
Custom Options
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 better-sqlite3
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
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 ?
}
Generate Prisma client:
npx prisma generate
npx prisma migrate dev --name init
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
Name of the Prisma model to use (case-sensitive).
Number of times to retry database connection.
connectionRetryIntervalMs
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
Cloudflare Worker
Lazy Initialization
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
Adapter Best For Auto-Migrations Connection Pooling Serverless PostgreSQL Production apps Yes Yes No MySQL Production apps Yes Yes No Redis High-traffic apps Yes Yes Yes MongoDB Flexible schemas No Yes Yes DynamoDB AWS serverless No N/A Yes SQLite Development Yes No No Drizzle Type-safe SQL No Depends Depends Prisma Modern workflows No Yes Depends KV Cloudflare Workers No N/A Yes Memory Development only N/A N/A No
Next Steps
SessionStorage Interface Learn about the core interface
Overview Session storage concepts