Skip to main content
This guide covers important considerations and best practices for deploying OrgStack in a production environment.

Environment configuration

Never hardcode credentials or sensitive configuration in production. Use environment variables to configure your application.

Database connection

Override the default configuration using environment variables:
# Database connection
export SPRING_DATASOURCE_URL=jdbc:postgresql://your-db-host:5432/orgstack_prod
export SPRING_DATASOURCE_USERNAME=orgstack_prod_user
export SPRING_DATASOURCE_PASSWORD=your-secure-password

# Server configuration
export SERVER_PORT=8080
Never commit production credentials to version control. Use secret management services like AWS Secrets Manager, HashiCorp Vault, or your cloud provider’s equivalent.

JPA and Hibernate configuration

The default application.properties is already configured for production with spring.jpa.hibernate.ddl-auto=validate:
spring.jpa.hibernate.ddl-auto=validate
The validate setting ensures Hibernate validates the database schema against your entities but doesn’t make any changes. This prevents accidental schema modifications in production.
  • validate (recommended for production): Validates the schema, makes no changes to the database
  • update: Updates the schema if necessary (risky in production)
  • create: Creates the schema, destroying previous data (never use in production)
  • create-drop: Creates the schema, drops it when SessionFactory closes (for testing only)
  • none: Does nothing with the schema
Never use create, create-drop, or update in production. Always use validate or none.

Database setup

1

Use a managed database service

For production, use a managed PostgreSQL service from your cloud provider:
  • AWS: Amazon RDS for PostgreSQL
  • Google Cloud: Cloud SQL for PostgreSQL
  • Azure: Azure Database for PostgreSQL
  • DigitalOcean: Managed Databases
  • Heroku: Heroku Postgres
Managed services provide automatic backups, high availability, and maintenance.
2

Configure connection pooling

Spring Boot uses HikariCP by default for connection pooling. Configure it for production workloads:
# Connection pool configuration
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.idle-timeout=600000
spring.datasource.hikari.max-lifetime=1800000
Or using environment variables:
export SPRING_DATASOURCE_HIKARI_MAXIMUM_POOL_SIZE=10
export SPRING_DATASOURCE_HIKARI_MINIMUM_IDLE=5
export SPRING_DATASOURCE_HIKARI_CONNECTION_TIMEOUT=30000
Adjust maximum-pool-size based on your expected load and database connection limits.
3

Use SSL for database connections

Enable SSL for secure database connections:
spring.datasource.url=jdbc:postgresql://your-db-host:5432/orgstack_prod?sslmode=require
Most managed database services require or strongly recommend SSL connections.

Database migrations

Since ddl-auto is set to validate, you need a migration strategy for schema changes:
1

Use Flyway or Liquibase

Add a database migration tool to manage schema changes:Flyway (recommended for Spring Boot):
<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
</dependency>
<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-database-postgresql</artifactId>
</dependency>
Create migration scripts in src/main/resources/db/migration/:
db/migration/
├── V1__initial_schema.sql
├── V2__add_organizations_table.sql
└── V3__add_users_table.sql
2

Version your migrations

Use semantic versioning for migration files:
  • V1__description.sql - First migration
  • V2__description.sql - Second migration
  • V3__description.sql - Third migration
Never modify a migration that has already been applied to production. Always create a new migration to make additional changes.

Security considerations

1

Use strong passwords

Generate strong, unique passwords for database users:
# Generate a secure password (Linux/macOS)
openssl rand -base64 32
The development password orgstack_dev_password from application.properties must never be used in production.
2

Restrict database access

Configure your database firewall to only allow connections from your application servers:
  • Use security groups (AWS) or firewall rules (GCP, Azure)
  • Whitelist only your application server IPs
  • Never expose PostgreSQL directly to the internet
3

Enable Spring Security

OrgStack includes Spring Security. Configure authentication and authorization for your endpoints:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
    // Configure security rules
}
Review and configure Spring Security settings appropriate for your use case before deploying to production.
4

Use HTTPS

Always use HTTPS in production. Configure your reverse proxy (nginx, Apache) or cloud load balancer to handle SSL/TLS termination.

Building for production

Create an optimized production build:
cd backend
./mvnw clean package -DskipTests
This creates an executable JAR in target/backend-0.0.1-SNAPSHOT.jar.
Run tests in your CI/CD pipeline before building the production artifact. The -DskipTests flag is used here for faster builds when tests have already passed.

Running in production

Run the Spring Boot application as a standalone JAR:
java -jar -Xmx512m -Xms256m \
  -Dspring.profiles.active=production \
  backend-0.0.1-SNAPSHOT.jar
Adjust JVM memory settings (-Xmx, -Xms) based on your server resources and application needs.

Monitoring and observability

Spring Boot Actuator is already included in the pom.xml. Configure it for production:
# Actuator configuration
management.endpoints.web.exposure.include=health,info,metrics,prometheus
management.endpoint.health.show-details=when-authorized
management.metrics.export.prometheus.enabled=true
1

Health checks

Use the health endpoint for liveness and readiness probes:
curl http://localhost:8080/actuator/health
In Kubernetes, configure liveness and readiness probes to use this endpoint.
2

Metrics

Collect and monitor metrics using Prometheus:
curl http://localhost:8080/actuator/prometheus
Configure Prometheus to scrape this endpoint for metrics.
3

Application logs

Configure structured logging in production:
logging.level.root=INFO
logging.level.com.orgstack=INFO
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %logger{36} - %msg%n
# JSON logging for log aggregation
logging.file.name=/var/log/orgstack/application.log
Use a log aggregation service like ELK Stack, Splunk, or your cloud provider’s logging service.

Backup and disaster recovery

1

Regular database backups

Configure automated backups:
  • Use your managed database service’s backup feature
  • Set retention period (e.g., 30 days)
  • Enable point-in-time recovery if available
  • Test restore procedures regularly
2

Application state

Ensure your application is stateless:
  • Store session data in Redis or a database
  • Use external storage for file uploads (S3, Cloud Storage)
  • Design for horizontal scaling
3

Disaster recovery plan

Document and test your disaster recovery procedures:
  1. Database restore process
  2. Application redeployment steps
  3. DNS failover procedures
  4. Communication plan for stakeholders

Performance optimization

Optimize JVM settings for your workload:
java -jar \
  -Xmx1g -Xms1g \
  -XX:+UseG1GC \
  -XX:MaxGCPauseMillis=200 \
  -XX:+UseStringDeduplication \
  app.jar
Add indexes for frequently queried columns:
CREATE INDEX idx_organization_name ON organizations(name);
CREATE INDEX idx_user_email ON users(email);
Monitor slow queries and add indexes as needed.
Implement caching for frequently accessed data:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
Use Redis or Caffeine for distributed caching.

Scaling considerations

1

Horizontal scaling

Run multiple instances behind a load balancer:
  • Use a cloud load balancer (ALB, Cloud Load Balancing)
  • Configure health checks
  • Use session affinity if needed (or make the app stateless)
2

Database scaling

As your application grows:
  • Use read replicas for read-heavy workloads
  • Implement connection pooling (HikariCP is already configured)
  • Consider database sharding for very large datasets
3

Auto-scaling

Configure auto-scaling based on metrics:
  • CPU utilization
  • Memory usage
  • Request count
  • Response time

Checklist for production deployment

Before deploying to production, verify:
  • Database credentials are stored in secrets manager
  • spring.jpa.hibernate.ddl-auto is set to validate
  • SSL/TLS is enabled for database connections
  • HTTPS is configured for all endpoints
  • Health checks are configured
  • Monitoring and alerting are set up
  • Automated backups are enabled
  • Log aggregation is configured
  • Security scanning has been performed
  • Load testing has been completed
  • Disaster recovery plan is documented and tested

Next steps

Local development

Set up your local development environment

Docker setup

Use Docker for development and testing

Build docs developers (and LLMs) love