Spring Boot With PostgreSQL On Heroku
In modern cloud-native applications, deploying backend services on platforms like Heroku and connecting them to managed databases such as PostgreSQL is a common practice. Heroku provides a fully managed PostgreSQL service (Heroku Postgres), which simplifies database provisioning, scaling, and maintenance. Let us delve into understanding Spring Boot, PostgreSQL, and Heroku.
1. Introduction to Heroku Platform
Heroku is a cloud Platform as a Service (PaaS) that enables developers to build, run, and deploy applications without worrying about underlying infrastructure management. It abstracts away complexities such as server provisioning, load balancing, scaling, and maintenance, allowing developers to focus purely on application development. With support for multiple programming languages including Java, Node.js, Python, and more, Heroku provides a flexible environment for modern application development.
One of the key concepts in Heroku is the use of dynos, which are lightweight, isolated containers that run your application processes. These dynos can be scaled horizontally to handle increased traffic, making Heroku highly suitable for scalable applications. Additionally, Heroku follows a strict twelve-factor app methodology, encouraging best practices such as environment-based configuration, stateless processes, and dependency management.
Heroku also offers a rich ecosystem of add-ons, which are third-party services that can be easily integrated into your application. One of the most commonly used add-ons is Heroku Postgres, a fully managed PostgreSQL database service. It handles tasks such as backups, replication, failover, and scaling, significantly reducing operational overhead for developers.
Another important aspect of Heroku is its use of environment variables for configuration. Instead of hardcoding sensitive information like database credentials, Heroku provides them dynamically through variables such as DATABASE_URL. This approach improves security and makes applications more portable across environments.
Deployment on Heroku is also streamlined through Git-based workflows. Developers can push their code directly to Heroku, which then automatically detects the application type, installs dependencies, builds the project, and deploys it. This continuous deployment-like experience makes it extremely efficient to iterate and release updates quickly.
Overall, Heroku simplifies the process of deploying and managing backend services, especially when combined with managed databases like PostgreSQL. It is an excellent choice for developers looking to build cloud-native applications with minimal infrastructure management while maintaining scalability, reliability, and ease of use.
2. End-to-End Implementation
2.1 Prerequisites and Environment Setup
To get started, ensure you have Java 17 or a later version installed on your system, along with a properly configured Spring Boot project. You should also have the Heroku CLI installed and set up to manage deployments and interact with your Heroku environment. Additionally, Git must be installed and configured, as it is required for version control and deploying your application to Heroku using Git-based workflows.
2.2 Project Initialization (Spring Initializr)
You can generate a Spring Boot project using Spring Initializr by selecting the required dependencies such as Spring Web for building RESTful APIs, Spring Data JPA for database interaction and ORM support, and the PostgreSQL Driver for connecting your application to a PostgreSQL database. These dependencies provide a solid foundation for building and integrating your application with a relational database.
2.3 Setting Up Heroku and PostgreSQL
Before deploying your Spring Boot application, you need to set up your Heroku environment. This includes authenticating your account, creating a new Heroku application, and provisioning a managed PostgreSQL database. Heroku provides an easy-to-use CLI that simplifies these steps and allows you to manage your application directly from the terminal.
# Login to Heroku heroku login # Create app heroku create your-app-name # Add PostgreSQL addon heroku addons:create heroku-postgresql:hobby-dev
Once these steps are completed, your Heroku application will be ready with a provisioned PostgreSQL instance. You can verify the database credentials using the Heroku dashboard or CLI, and then proceed to configure your Spring Boot application to connect to this database using the provided environment variables.
2.4 Adding Required Dependencies
To enable database interaction in your Spring Boot application, you need to include the required dependencies in your pom.xml file. These dependencies allow your application to use JPA for ORM (Object Relational Mapping) and establish a connection with a PostgreSQL database. Spring Boot simplifies configuration by auto-configuring many components based on these dependencies.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
</dependencies>
The spring-boot-starter-data-jpa dependency provides support for working with relational databases using JPA and Hibernate, including features like entity management, repositories, and transaction handling. The PostgreSQL driver dependency enables your application to communicate with a PostgreSQL database by handling the low-level connection details. Once these are added, Spring Boot will automatically configure the datasource if the necessary database properties are provided.
2.5 Configuring Database Connection (DATABASE_URL)
Once your PostgreSQL database is provisioned on Heroku, the platform automatically provides the connection details through an environment variable called DATABASE_URL. This URL contains all the necessary information such as username, password, host, port, and database name in a single string. Understanding this format is important before integrating it with your Spring Boot application.
Heroku provides the database URL in the following format:
postgres://username:password@host:port/dbname
However, Spring Boot does not natively support this URL format. Instead, it expects individual properties like spring.datasource.url, username, and password. Therefore, you need to parse this URL and extract the required components so they can be configured properly within your application. This step ensures a successful connection between your Spring Boot application and the Heroku PostgreSQL database.
2.6 Custom DataSource Configuration
To connect your Spring Boot application with the Heroku PostgreSQL database, you need to programmatically configure a DataSource. Since Heroku provides the database connection as a single environment variable (DATABASE_URL), this configuration class parses that URL and converts it into a format that Spring Boot understands. This approach ensures your application can dynamically read database credentials at runtime without hardcoding them.
// DataSourceConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.net.URI;
import org.springframework.boot.jdbc.DataSourceBuilder;
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource() {
try {
String databaseUrl = System.getenv("DATABASE_URL");
URI dbUri = new URI(databaseUrl);
String username = dbUri.getUserInfo().split(":")[0];
String password = dbUri.getUserInfo().split(":")[1];
String jdbcUrl = "jdbc:postgresql://" + dbUri.getHost() + ":" + dbUri.getPort() + dbUri.getPath();
return DataSourceBuilder.create()
.url(jdbcUrl)
.username(username)
.password(password)
.driverClassName("org.postgresql.Driver")
.build();
} catch (Exception e) {
throw new RuntimeException("Failed to configure DataSource", e);
}
}
}
This configuration reads the DATABASE_URL environment variable provided by Heroku and converts it into a standard JDBC URL required by Spring Boot. It extracts the username and password from the URL, constructs the JDBC connection string, and uses DataSourceBuilder to create a fully configured DataSource bean. By defining this as a @Bean, Spring Boot automatically uses it across the application for database operations.
2.7 Defining JPA Entity
In a Spring Boot application using JPA, an entity represents a table in the database. Each instance of the entity corresponds to a row in that table. To map your Java class to a database table, you use JPA annotations such as @Entity, which tells Spring Boot and Hibernate to treat this class as a persistent entity.
// User.java
import jakarta.persistence.*;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// getters and setters
}
In this example, the User class is mapped to a database table (by default, the table name will be user). The @Id annotation marks the primary key of the table, while @GeneratedValue with GenerationType.IDENTITY ensures that the database automatically generates unique values for the id field. The name field is mapped to a column in the table. Getters and setters are required for JPA to access and manage the entity’s state. Once defined, this entity can be used with Spring Data JPA repositories to perform CRUD operations seamlessly.
2.8 Creating Repository Layer
After defining your entity, the next step is to create a repository interface that will handle database operations. Spring Data JPA provides a powerful abstraction that eliminates the need to write boilerplate SQL queries. By simply extending the JpaRepository interface, you automatically get access to a wide range of CRUD operations such as saving, updating, deleting, and fetching data from the database.
// UserRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}
In this example, UserRepository manages the User entity with a primary key of type Long. Spring Boot will automatically create the implementation of this interface at runtime. You can use built-in methods like save(), findById(), findAll(), and deleteById() without writing any SQL. Additionally, you can define custom query methods by following naming conventions, such as findByName(String name), and Spring Data JPA will generate the query automatically.
2.9 Building REST Controller
The controller layer is responsible for handling incoming HTTP requests and returning appropriate responses. In a Spring Boot application, @RestController is used to expose RESTful APIs, allowing clients to interact with your application. This layer acts as a bridge between the client and the repository, processing requests and delegating database operations to the repository layer.
// UserController.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserRepository repository;
@PostMapping
public User createUser(@RequestBody User user) {
return repository.save(user);
}
@GetMapping
public List<User> getUsers() {
return repository.findAll();
}
}
In this example, the @RequestMapping("/users") defines the base URL for all endpoints in this controller. The @PostMapping endpoint allows clients to create a new user by sending a JSON request body, which is automatically mapped to the User object using @RequestBody. The @GetMapping endpoint retrieves all users from the database. The @Autowired annotation injects the UserRepository, enabling seamless interaction with the database. This setup provides a simple yet effective REST API for performing basic CRUD operations.
2.10 Application Configuration (application.properties)
The application.properties file is used to configure various settings for your Spring Boot application. In this case, it includes important configurations related to JPA, Hibernate, and server behavior. These properties help control how your application interacts with the PostgreSQL database and how it runs in different environments, including Heroku.
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
server.port=${PORT:8080}
The spring.jpa.hibernate.ddl-auto=update property ensures that Hibernate automatically updates the database schema based on your entity classes without dropping existing data. The spring.jpa.show-sql=true setting enables logging of SQL queries in the console, which is useful for debugging and development. The Hibernate dialect is set to PostgreSQL to ensure compatibility with the database. Finally, server.port=${PORT:8080} allows the application to use the port assigned by Heroku dynamically, defaulting to 8080 when running locally. This configuration ensures your application runs smoothly both in local and cloud environments.
2.11 Deploying Application to Heroku
Once your application is fully configured and tested locally, the final step is to deploy it to Heroku. Heroku uses Git-based deployment, which makes the process straightforward if your project is already under version control. You will initialize a Git repository (if not already done), commit your code, and push it to the Heroku remote repository to trigger the deployment.
git init git add . git commit -m "Initial commit" heroku git:remote -a your-app-name git push heroku master
The git init command initializes a new Git repository, while git add . and git commit stage and save your project files. The heroku git:remote command links your local repository to your Heroku application. Finally, git push heroku master uploads your code to Heroku, which automatically builds and deploys the application. Once the deployment is complete, you can access your live application using the URL provided by Heroku.
2.11.1 Deployment Output and API Testing
After successfully deploying your application to Heroku, the platform will automatically build and start your Spring Boot application. You can monitor the deployment process and application logs using the Heroku CLI to ensure everything is running correctly. Once the application is up, it will be accessible via the public URL generated by Heroku.
-----> Building on the Heroku platform -----> Detecting Java app -----> Installing OpenJDK 17 -----> Building with Maven -----> Deploying... -----> Launching... Released v1 https://your-app-name.herokuapp.com deployed to Heroku
You can test the deployed APIs using tools like Postman or curl. For example, sending a POST request to /users will create a new user, and a GET request to the same endpoint will return the list of users stored in the PostgreSQL database.
--- (1)
POST /users
Request:
{
"name": "John Doe"
}
Response:
{
"id": 1,
"name": "John Doe"
}
--- (2)
GET /users
Response:
[
{
"id": 1,
"name": "John Doe"
}
]
This confirms that your Spring Boot application is successfully connected to Heroku and functioning as expected.
3. Conclusion
Connecting a Spring Boot application to Heroku Postgres involves parsing the provided DATABASE_URL and configuring a proper DataSource. Once set up, Spring Data JPA handles most of the database interactions seamlessly. This setup is production-ready and scalable, making it ideal for deploying cloud-native Java applications with minimal operational overhead.




