Developer Guide
Self-host Transi-Store on your own infrastructure.
Self-Hosting Overview
Transi-Store is fully open-source and can be self-hosted on your own infrastructure. You get the same features as the cloud version, without any usage limits.
The application is a React Router v7 SSR application backed by PostgreSQL. The recommended way to run it is with Docker Compose.
Requirements
| Requirement | Version |
|---|---|
| Docker | 24+ |
| Docker Compose | v2+ |
| RAM | 512 MB minimum |
| Disk | 1 GB minimum |
You do not need Node.js or Yarn on the host machine — everything runs inside Docker.
At least one OAuth provider (Google or GitHub) must be configured for authentication.
Installation
1. Clone the repository
git clone https://github.com/transi-store/transi-store.git
cd transi-store
2. Configure environment variables
Copy the example environment file and fill in the required values:
cp .env.example .env
Open .env and configure at minimum:
# Required — generate with: openssl rand -hex 32
SESSION_SECRET=a-long-random-string
# Required — generate with: openssl rand -hex 32
ENCRYPTION_KEY=64-char-hex-string
# Required — at least one OAuth provider
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
# Required — public URL used for OAuth redirect URIs
DOMAIN_ROOT=https://your-domain.com
Note: DATABASE_URL is pre-configured for the Docker Compose setup and does not need to change unless you use an external database.
3. Start the application
make setup # First time only — installs dependencies and creates the database schema
make dev # Development server at http://localhost:5173
For a production build:
make build # Build the application
make up # Start production Docker containers
Configuration
Environment variables
| Variable | Required | Description |
|---|---|---|
SESSION_SECRET | Yes | Secret used to sign session cookies |
ENCRYPTION_KEY | Yes | 64-char hex key for encrypting API keys |
DATABASE_URL | Yes | PostgreSQL connection string |
GOOGLE_CLIENT_ID | At least one provider | Google OAuth client ID |
GOOGLE_CLIENT_SECRET | At least one provider | Google OAuth client secret |
GITHUB_CLIENT_ID | At least one provider | GitHub OAuth app client ID |
GITHUB_CLIENT_SECRET | At least one provider | GitHub OAuth app client secret |
DOMAIN_ROOT | Yes | Public URL of your instance (used for OAuth redirect URIs) |
Setting up OAuth providers
Google OAuth:
- Go to Google Cloud Console.
- Create a new OAuth 2.0 client ID (type: Web application).
- Add
https://your-domain.com/auth/google/callbackas an authorized redirect URI. - Copy the Client ID and Client Secret to your
.envfile.
GitHub OAuth:
- Go to GitHub Developer Settings.
- Create a new OAuth App.
- Set the Authorization callback URL to
https://your-domain.com/auth/github/callback. - Copy the Client ID and generate a Client Secret for your
.envfile.
Running in Production
Docker Compose (recommended)
The repository ships with a production-ready docker-compose.yml. After configuring your .env file:
make up # Start all services (app + PostgreSQL)
make logs # Follow logs
make down # Stop all services
The application listens on port 5173 by default. Use a reverse proxy (nginx, Caddy, Traefik) to expose it on port 443 with HTTPS.
Reverse proxy example (nginx)
server {
listen 443 ssl;
server_name transi.example.com;
location / {
proxy_pass http://localhost:5173;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto https;
}
}
Database management
make db-push # Apply schema changes after updating to a new version
make db-studio # Open Drizzle Studio GUI in your browser
make db-reset # Warning: wipe and recreate the database (destructive!)
Upgrading: after pulling a new version, run make db-push to apply any schema changes before restarting.
CLI Tool
The @transi-store/cli package provides a command-line interface for syncing translations in CI/CD pipelines.
Installation
npm install -g @transi-store/cli
# or add to your project
npm install --save-dev @transi-store/cli
Configuration
Create a transi-store.config.json at the root of your project:
{
"$schema": "https://unpkg.com/@transi-store/cli/schema.json",
"org": "acme",
"projects": [
{
"project": "webapp",
"langs": ["en", "fr", "de"],
"format": "json",
"output": "./src/locales/<lang>/translations.json"
}
]
}
Set the TRANSI_STORE_API_KEY environment variable with your API key, then run:
Downloading translations
# Download all translations using the config file
transi-store download:config
# Download for a specific branch
transi-store download:config --branch feature/my-feature
# Download for a single project/locale without a config file
transi-store download --org acme --project webapp --locale fr --output ./locales/fr.json
Git branch auto-detection: when --branch is not provided, the CLI automatically detects the current git branch and uses it. On main/master, no branch filter is applied (main translations are fetched).
Uploading translations
# Upload all translation files using the config file
transi-store upload:config
# Upload for a specific branch
transi-store upload:config --branch feature/my-feature
# Upload a single file without a config file
transi-store upload --org acme --project webapp --locale fr --input ./locales/fr.json
Git branch auto-detection: when --branch is not provided, the CLI automatically detects the current git branch and uses it. On main/master, no branch filter is applied (keys are uploaded to the main project).
Git optimization: upload:config also skips files that have not changed compared to the default branch (main/master) when running in a git repository, to avoid unnecessary API calls.
This is ideal for integrating into CI/CD — download translated strings at build time and upload new source strings after developers add them.