Deploy Papermark
Papermark: Your #1 alternative to Docsend. Open Source.
Just deployed
/var/lib/postgresql/data
Just deployed
Deploy and Host Papermark on Railway
Papermark is an open-source document sharing and data room platform. It lets you share pitch decks, proposals, contracts, and any document through a trackable link with page-by-page analytics, email capture, password protection, custom branding, and your own domain.
About Hosting Papermark
This template clones the upstream mfts/papermark repository and builds it inside a multi-stage Dockerfile on Node 22. Prisma generates the database client at build time and migrations run automatically at container startup via prisma migrate deploy. The app listens on port 3000 and connects to PostgreSQL through POSTGRES_PRISMA_URL. Document uploads require blob storage: either a Vercel Blob token or S3-compatible credentials (AWS, MinIO, Cloudflare R2). Email notifications require a Resend API key. Google OAuth and passkey login are optional.
Common Use Cases
- Sharing pitch decks with investors and tracking who viewed each slide and for how long
- Sending proposals and contracts with email verification, NDA acceptance, and download controls
- Running virtual data rooms for due diligence with granular viewer permissions and audit trails
Dependencies for Papermark Hosting
- Railway PostgreSQL plugin (provisioned automatically by the template)
- Blob storage for documents: Vercel Blob token or S3/R2/MinIO credentials
- Resend API key for transactional emails (optional but recommended)
- Google OAuth credentials for social login (optional; email magic link works without it)
Deployment Dependencies
- Papermark — upstream open-source project (AGPL-3.0)
- Next.js 14 — React framework
- Prisma 6 — database ORM and migrations
- Resend — transactional email API
- Railway — hosting platform
Why Deploy Papermark on Railway?
Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.
By deploying Papermark on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.
What's Inside
| Layer | Technology | Role |
|---|---|---|
| Frontend | Next.js 14 + Tailwind + Radix UI | Dashboard, viewer, link pages |
| Auth | NextAuth.js | Google OAuth, email, passkeys |
| Database | PostgreSQL + Prisma | Users, documents, views, analytics |
| Storage | Vercel Blob or S3-compatible | Uploaded PDFs, images, videos |
| Resend | Notifications, viewer invitations |
Deploy to Railway
- Click the Deploy on Railway button above
- Railway provisions PostgreSQL automatically
- Set the required environment variables (see below)
- The Dockerfile clones Papermark, builds it, and runs migrations on start
- Open your Railway public domain and create your account
Environment Variables
Required (web service)
POSTGRES_PRISMA_URL="${{Postgres.DATABASE_URL}}" # Prisma connection pooling URL
POSTGRES_PRISMA_URL_NON_POOLING="${{Postgres.DATABASE_URL}}" # direct URL for migrations
NEXTAUTH_SECRET="${{ secret(32, \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\") }}" # session encryption key
NEXTAUTH_URL="https://your-app.up.railway.app" # your Railway public URL (update after first deploy)
NEXT_PUBLIC_BASE_URL="https://your-app.up.railway.app" # same as NEXTAUTH_URL
Storage (pick one)
Option A: Vercel Blob (easiest, free tier available)
NEXT_PUBLIC_UPLOAD_TRANSPORT="vercel"
BLOB_READ_WRITE_TOKEN="" # from vercel.com/dashboard/stores
Option B: S3-compatible (AWS, R2, MinIO)
NEXT_PUBLIC_UPLOAD_TRANSPORT="s3"
NEXT_PRIVATE_UPLOAD_BUCKET="your-bucket"
NEXT_PRIVATE_UPLOAD_REGION="us-east-1"
NEXT_PRIVATE_UPLOAD_ACCESS_KEY_ID=""
NEXT_PRIVATE_UPLOAD_SECRET_ACCESS_KEY=""
NEXT_PRIVATE_UPLOAD_DISTRIBUTION_HOST="your-bucket.s3.us-east-1.amazonaws.com"
Optional
RESEND_API_KEY="" # transactional emails (viewer notifications, invitations)
GOOGLE_CLIENT_ID="" # Google OAuth login
GOOGLE_CLIENT_SECRET="" # Google OAuth login
NEXT_PRIVATE_DOCUMENT_PASSWORD_KEY="" # encryption key for document passwords
Railway template: PostgreSQL service variables
PGDATA="" # data directory (volume); often set by the image
PGHOST="${{RAILWAY_PRIVATE_DOMAIN}}" # private hostname for other Railway services
PGPORT="" # omit for default 5432, or set explicitly
PGUSER="${{POSTGRES_USER}}" # DB role; keep aligned with POSTGRES_USER
PGDATABASE="${{POSTGRES_DB}}" # database name
PGPASSWORD="${{POSTGRES_PASSWORD}}" # password for PGUSER
POSTGRES_DB="papermark" # DB created on first init
DATABASE_URL="postgresql://${{PGUSER}}:${{POSTGRES_PASSWORD}}@${{RAILWAY_PRIVATE_DOMAIN}}:5432/${{PGDATABASE}}" # in-cluster connection string
POSTGRES_USER="papermark" # superuser name on first init
POSTGRES_PASSWORD="${{ secret(32, \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\") }}" # generated root password
DATABASE_PUBLIC_URL="postgresql://${{PGUSER}}:${{POSTGRES_PASSWORD}}@${{RAILWAY_TCP_PROXY_DOMAIN}}:${{RAILWAY_TCP_PROXY_PORT}}/${{PGDATABASE}}" # TCP proxy for external clients
Template icon (Railway): assets/icon.png · assets/icon.svg
Local Development
git clone https://github.com/mfts/papermark.git
cd papermark
cp .env.example .env
# Edit .env with your Postgres URL, storage, and auth config
npm install
npx prisma generate
npx prisma migrate deploy
npm run dev
Open http://localhost:3000.
License
Built by AToolZ
Template Content
PGDATA
data directory (volume mount path); often set by the image
PGPORT
leave empty for default 5432, or set an explicit port
SSL_CERT_DAYS
optional TLS cert lifetime if you generate certs
RAILWAY_DEPLOYMENT_DRAINING_SECONDS
drain window during deploys
QSTASH_TOKEN
Upstash QStash token for background jobs and queues (https://upstash.com)
HANKO_API_KEY
Hanko Passkey API key; required for passkey login (https://docs.hanko.io)
RESEND_API_KEY
Resend API key for magic-link and notification emails (https://resend.com)
TINYBIRD_TOKEN
Tinybird token for analytics event ingestion (optional)
GOOGLE_CLIENT_ID
Google OAuth client ID for social login
TRIGGER_SECRET_KEY
Trigger.dev secret key for background task orchestration (optional)
GOOGLE_CLIENT_SECRET
Google OAuth client secret paired with the client ID above
BLOB_READ_WRITE_TOKEN
Vercel Blob read/write token; only needed if UPLOAD_TRANSPORT=vercel
UPSTASH_REDIS_REST_URL
Upstash Redis REST endpoint for rate limiting (https://console.upstash.com)
QSTASH_NEXT_SIGNING_KEY
next (rotated) QStash signing key; used during key rotation
UPSTASH_REDIS_REST_TOKEN
Upstash Redis REST token paired with the URL above
NEXT_PRIVATE_UPLOAD_BUCKET
S3 bucket name for document storage
QSTASH_CURRENT_SIGNING_KEY
current QStash webhook signature key for request verification
NEXT_PUBLIC_HANKO_TENANT_ID
Hanko tenant ID paired with the API key above
NEXT_PRIVATE_UPLOAD_ENDPOINT
S3-compatible endpoint URL; leave empty for AWS S3
UPSTASH_REDIS_REST_LOCKER_URL
Upstash Redis REST endpoint for tus.io bulk-upload locking
UPSTASH_REDIS_REST_LOCKER_TOKEN
Upstash Redis REST token for the locker instance
NEXT_PRIVATE_UPLOAD_ACCESS_KEY_ID
S3 access key ID
NEXT_PRIVATE_UPLOAD_DISTRIBUTION_HOST
CDN hostname (CloudFront, S3, or Blob) used in next.config.mjs image remotes
NEXT_PRIVATE_UPLOAD_SECRET_ACCESS_KEY
S3 secret access key