Skip to main content
POS Kasir uses environment variables for configuration. This guide covers all available settings and how to configure them.

Environment Files

POS Kasir uses two environment files:
  • .env - Backend configuration (Go API)
  • web/.env - Frontend configuration (TanStack Start)
1

Create Environment Files

Copy the example files:
cp .env.example .env
cp web/.env.example web/.env
2

Configure Backend

Edit .env with your settings (see sections below)
3

Configure Frontend

Edit web/.env with your API endpoint:
VITE_API_BASE=http://localhost:8080/api/v1

Backend Configuration

Server & Application

Basic application settings:
.env
# Environment: production or development
APP_ENV=development

# Application name
APP_NAME=POS-Kasir

# Server port
APP_PORT=8080

# Cookie domain (leave empty for localhost)
COOKIE_DOMAIN=

# Allow cross-origin requests from frontend
WEB_FRONTEND_CROSS_ORIGIN=false
APP_ENV
string
default:"development"
Set to production in production environment. Affects logging and error handling.
APP_PORT
number
default:"8080"
Port where the backend API will listen. Must match Docker port mapping if using Docker.
WEB_FRONTEND_CROSS_ORIGIN
boolean
default:"false"
Enable if frontend is on different domain. Set to true in production with separate domains.

Database Configuration

PostgreSQL database settings:
.env
# Database host (use 'localhost' for local, service name for Docker)
DB_HOST=localhost

# Database port
DB_PORT=5432

# Database credentials
DB_USER=postgres
DB_PASSWORD=your_secure_password
DB_NAME=pos_kasir

# SSL mode: disable, require, verify-ca, verify-full
DB_SSLMODE=disable

# Connection pool settings
DB_MAX_OPEN_CONNECTIONS=10
DB_MAX_IDLE_CONNECTIONS=2
DB_MAX_LIFETIME_MINUTES=10
Always use strong passwords for DB_PASSWORD in production environments.
DB_HOST
string
required
Database host. Use localhost for local development, or container name when using Docker.
DB_SSLMODE
string
default:"disable"
SSL mode for database connection. Use require or higher in production.
DB_MAX_OPEN_CONNECTIONS
number
default:"10"
Maximum number of open connections to database. Tune based on load.

Migration Settings

Database migration configuration:
.env
# Auto-run migrations on startup (not recommended for production)
AUTO_MIGRATE=false

# Path to migration files
MIGRATIONS_PATH=./sqlc/migrations
Keep AUTO_MIGRATE=false in production. Run migrations manually using make migrate-up.

Logging Configuration

Configure application logging:
.env
# Log level: debug, info, warn, error
LOG_LEVEL=info

# Output logs in JSON format
LOG_JSON_FORMAT=false
LOG_LEVEL
string
default:"info"
Logging level. Use debug for development, info or warn for production.
LOG_JSON_FORMAT
boolean
default:"false"
Enable JSON logging for production log aggregation systems.

JWT Authentication

JSON Web Token settings for user authentication:
.env
# Secret key for signing JWT tokens (use strong random string)
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production

# Token expiration in hours
JWT_DURATION_HOURS=24

# JWT issuer identifier
JWT_ISSUER=poskasir
Critical: Generate a strong random JWT_SECRET for production:
openssl rand -base64 64
Never commit this secret to version control!
JWT_SECRET
string
required
Secret key for signing JWT tokens. Must be strong and unique in production.
JWT_DURATION_HOURS
number
default:"24"
Token validity period in hours. Balance security with user experience.

Midtrans Payment Gateway

Configuration for Midtrans digital payment integration:
.env
# Midtrans server key (get from Midtrans dashboard)
MIDTRANS_SERVER_KEY=your-midtrans-server-key

# Use production environment (false = sandbox mode)
MIDTRANS_IS_PROD=false
Get your Midtrans credentials from Midtrans Dashboard:
  • Sandbox: For testing
  • Production: For real transactions
MIDTRANS_SERVER_KEY
string
Server key from Midtrans dashboard. Use sandbox key for testing.
MIDTRANS_IS_PROD
boolean
default:"false"
Set to true only when using production credentials and real payments.
  1. Sign up at Midtrans
  2. Go to SettingsAccess Keys
  3. Copy your Server Key
  4. Start with Sandbox mode for testing
  5. Switch to Production when ready for real payments

Cloudflare R2 Storage

Configuration for cloud object storage (for product images):
.env
# Cloudflare account ID
R2_ACCOUNT_ID=your-cloudflare-account-id

# R2 access credentials
R2_ACCESS_KEY=your-r2-access-key
R2_SECRET_KEY=your-r2-secret-key

# R2 bucket name
R2_BUCKET=pos-kasir

# Public domain for accessing images
R2_PUBLIC_DOMAIN=https://your-bucket.r2.dev

# Presigned URL expiry in seconds
R2_EXPIRY_SECONDS=3600
Cloudflare R2 provides S3-compatible object storage. Get credentials from Cloudflare Dashboard.
R2_ACCOUNT_ID
string
Your Cloudflare account ID from the dashboard.
R2_BUCKET
string
default:"pos-kasir"
Name of your R2 bucket. Create it in Cloudflare dashboard first.
R2_PUBLIC_DOMAIN
string
Public URL for accessing uploaded images. Configure in R2 bucket settings.
  1. Log in to Cloudflare Dashboard
  2. Go to R2Create Bucket
  3. Name your bucket (e.g., pos-kasir)
  4. Go to SettingsR2 API Tokens
  5. Create an API token with edit permissions
  6. Copy your Access Key and Secret Key
  7. Configure public access or custom domain for R2_PUBLIC_DOMAIN

Frontend Configuration

The frontend requires minimal configuration:
web/.env
# Backend API base URL
VITE_API_BASE=http://localhost:8080/api/v1
VITE_API_BASE
string
required
Full URL to the backend API. Include the /api/v1 path.

Environment-Specific URLs

VITE_API_BASE=http://localhost:8080/api/v1

Complete Configuration Example

# ==============================================
# Server & Application Config
# ==============================================
APP_ENV=development
APP_NAME=POS-Kasir
APP_PORT=8080
COOKIE_DOMAIN=
WEB_FRONTEND_CROSS_ORIGIN=false

# ==============================================
# Database (PostgreSQL)
# ==============================================
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=postgres
DB_NAME=pos_kasir
DB_SSLMODE=disable

DB_MAX_OPEN_CONNECTIONS=10
DB_MAX_IDLE_CONNECTIONS=2
DB_MAX_LIFETIME_MINUTES=10

# ==============================================
# Migration
# ==============================================
AUTO_MIGRATE=false
MIGRATIONS_PATH=./sqlc/migrations

# ==============================================
# Logger
# ==============================================
LOG_LEVEL=info
LOG_JSON_FORMAT=false

# ==============================================
# JWT (Authentication)
# ==============================================
JWT_SECRET=dev-secret-change-in-production
JWT_DURATION_HOURS=24
JWT_ISSUER=poskasir

# ==============================================
# Midtrans (Payment Gateway)
# ==============================================
MIDTRANS_SERVER_KEY=SB-Mid-server-your-sandbox-key
MIDTRANS_IS_PROD=false

# ==============================================
# Cloudflare R2 (Object Storage)
# ==============================================
R2_ACCOUNT_ID=your-account-id
R2_ACCESS_KEY=your-access-key
R2_SECRET_KEY=your-secret-key
R2_BUCKET=pos-kasir
R2_PUBLIC_DOMAIN=https://pos-kasir.r2.dev
R2_EXPIRY_SECONDS=3600
# ==============================================
# Server & Application Config
# ==============================================
APP_ENV=production
APP_NAME=POS-Kasir
APP_PORT=8080
COOKIE_DOMAIN=.yourdomain.com
WEB_FRONTEND_CROSS_ORIGIN=true

# ==============================================
# Database (PostgreSQL)
# ==============================================
DB_HOST=your-database-host.com
DB_PORT=5432
DB_USER=pos_user
DB_PASSWORD=strong-random-password-here
DB_NAME=pos_kasir_prod
DB_SSLMODE=require

DB_MAX_OPEN_CONNECTIONS=25
DB_MAX_IDLE_CONNECTIONS=5
DB_MAX_LIFETIME_MINUTES=15

# ==============================================
# Migration
# ==============================================
AUTO_MIGRATE=false
MIGRATIONS_PATH=./sqlc/migrations

# ==============================================
# Logger
# ==============================================
LOG_LEVEL=warn
LOG_JSON_FORMAT=true

# ==============================================
# JWT (Authentication)
# ==============================================
JWT_SECRET=use-openssl-rand-base64-64-to-generate-this
JWT_DURATION_HOURS=24
JWT_ISSUER=poskasir

# ==============================================
# Midtrans (Payment Gateway)
# ==============================================
MIDTRANS_SERVER_KEY=Mid-server-your-production-key
MIDTRANS_IS_PROD=true

# ==============================================
# Cloudflare R2 (Object Storage)
# ==============================================
R2_ACCOUNT_ID=your-production-account-id
R2_ACCESS_KEY=your-production-access-key
R2_SECRET_KEY=your-production-secret-key
R2_BUCKET=pos-kasir-prod
R2_PUBLIC_DOMAIN=https://cdn.yourdomain.com
R2_EXPIRY_SECONDS=3600

Security Best Practices

Follow these security practices for production deployments:
  • Never commit .env files to version control
  • Add .env to .gitignore
  • Use environment-specific secrets
  • Rotate secrets regularly
  • Use strong random strings for JWT_SECRET
  • Use strong passwords for DB_PASSWORD
  • Enable SSL with DB_SSLMODE=require in production
  • Limit database user permissions
  • Use separate databases for dev/staging/production
  • Regularly backup your database
  • Set APP_ENV=production in production
  • Enable WEB_FRONTEND_CROSS_ORIGIN only if needed
  • Set appropriate COOKIE_DOMAIN
  • Keep JWT_DURATION_HOURS reasonable (24-48 hours)
  • Use LOG_LEVEL=warn or error in production
  • Keep Midtrans in sandbox mode until ready
  • Restrict R2 bucket access appropriately
  • Use separate credentials for production
  • Monitor API usage and costs

Verification

After configuration, verify your settings:
1

Test Database Connection

make migrate-version
Should display current migration version without errors.
2

Check Application Startup

docker-compose up -d
docker-compose logs backend
Look for successful startup messages and no connection errors.
3

Test API Health

curl http://localhost:8080/api/v1/health
4

Verify Frontend Connection

Open browser to http://localhost:3000 and check browser console for API connection.

Next Steps

First Steps

Learn how to use POS Kasir after configuration

API Reference

Explore the API documentation

Build docs developers (and LLMs) love