> Markdown version of [Production Deployment](https://vaadin.com/docs/v14/flow/tutorial/production-deployment). Section index: [llms.txt](https://vaadin.com/docs/v14/flow/llms.txt)

# Deploying a Vaadin Flow Application on Heroku

> **Caution: This tutorial is for Vaadin 14.**
>
> If this is your first time trying out Vaadin, you should [read the same tutorial for the latest Vaadin version](/docs/flow/tutorial) instead.

In this final chapter in the series, you learn how to deploy a Spring Boot application on [Heroku](https://heroku.com).

This chapter covers:

- Vaadin production builds.

- Configuring PostgreSQL for production.

- Creating a Heroku account.

- Installing the Heroku CLI.

- Creating and deploying a Heroku app.

> **Tip: Vaadin can be deployed on any cloud provider**
>
> You can also deploy your application onto other cloud platforms. Read the [Cloud Deployment tutorials](https://vaadin.com/learn/tutorials/cloud-deployment) for more options.

## <a id="preparing-the-application-for-production"></a>Preparing the Application for Production

It’s important to build a separate, production-optimized version of the application before deploying it. In development mode, Vaadin has a live-reload widget, debug logging, and uses a quick, but unoptimized, frontend build that includes source maps for easy debugging. Unoptimized frontend bundles can contain several megabytes of JavaScript.

The `pom.xml` build includes a `production` profile configuration that prepares an optimized build which is ready for production.

### <a id="using-a-postgresql-database-in-production"></a>Using a PostgreSQL Database in Production

During development, the application uses an in-memory H2 database. This is convenient and works well for a single user. In production, it is better to use something more robust and persistent. Heroku’s free tier supports PostgreSQL, so you can configure your application to use that.

First, add the PostgreSQL dependency in the production profile of `pom.xml`:

`pom.xml`

```xml
<profile>
 <id>production</id>
 <!-- Omitted -->
 <dependencies>
   <dependency>
     <groupId>org.postgresql</groupId>
     <artifactId>postgresql</artifactId>
   </dependency>
 </dependencies>
</profile>
```

Next, configure how JPA should handle schema generation. Add the following two properties to the end of `application.properties`.

`src/main/java/resources/application.properties`

```
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create-drop
```

> **Warning: Avoid data loss**
>
> This setup recreates the database on every deployment. If you are working with real data, you should use `ddl-auto=none` and instead use a database migration tool like [Liquibase](https://www.liquibase.org/) or [Flyway](https://flywaydb.org/) so you can evolve the database schema without losing data.

### <a id="building-a-production-optimized-jar"></a>Building a Production-Optimized JAR

Build the application with the `production` profile:

```bash
mvn clean package -Pproduction
```

This builds a production-optimized JAR file in the `target` folder.

## <a id="creating-a-heroku-account-and-installing-the-heroku-cli"></a>Creating a Heroku Account and Installing the Heroku CLI

Complete the following steps to create a Heroku account and install the Heroku CLI.

1. Go to <https://signup.heroku.com/>, create a new account, and verify your email.

2. Go to <https://devcenter.heroku.com/articles/heroku-cli> and follow the instructions for installing the CLI on your operating system.

## <a id="deploying-a-vaadin-application-to-heroku"></a>Deploying a Vaadin Application to Heroku

Use the Heroku CLI to create and deploy your application.

1. Log in:

   ```terminal
   heroku login
   ```

2. Install the Heroku Java plugin:

   ```terminal
   heroku plugins:install java
   ```

3. Create a new app. Replace APPNAME with a name of your choice. APPNAME is part of the URL, like <https://APPNAME.herokuapp.com>, so choose a name that’s unique and easy to remember.

   ```terminal
   heroku create APPNAME
   ```

4. Enable the PostgreSQL plugin for the newly created app:

   ```terminal
   heroku addons:create heroku-postgresql -a APPNAME
   ```

5. Deploy the production-optimized JAR file you created in the previous section.

   ```terminal
   heroku deploy:jar target/flowcrmtutorial-1.0-SNAPSHOT.jar -a APPNAME
   ```

6. Open the application in your browser.

   ```terminal
   heroku open
   ```

7. In the event that something goes wrong, view the application logs.

   ```terminal
   heroku logs --tail
   ```

## <a id="conclusion-and-next-steps"></a>Conclusion and Next Steps

Congratulations, you have now built a full-stack PWA and deployed it to Heroku.

Did you like the tutorial? Did you find anything that didn’t seem right? Reach out to me on Twitter/X [@marcushellberg](https://x.com/marcushellberg) or visit the [Vaadin Forum](https://vaadin.com/forum).

Now that you have a running application, you can use it to experiment further or use it as a foundation for your next idea.

Happy hacking, and ping us [@vaadin](https://x.com/vaadin) on Twitter/X to show off the cool stuff you’ve built!

### <a id="helpful-links"></a>Helpful Links

- [Source code GitHub repository](https://github.com/vaadin-learning-center/crm-tutorial)

- [Vaadin Forum](https://vaadin.com/forum)

- [Stack Overflow](https://stackoverflow.com/questions/ask?tags=vaadin)

- [Flow documentation](https://vaadin.com/docs/v14/flow/overview.md)

- [Vaadin components](https://vaadin.com/docs/v14/ds/components.md)

- [Compare Vaadin with React, Angular, and Vue](https://vaadin.com/comparison)

<!-- vale Vale.Terms = NO --><!-- vale Vale.Spelling = NO --><!-- vale Vaadin.OneSentencePerLine = NO -->

[Image: migration assistance]

**Download free e-book.**\
The complete guide is also available in an easy-to-follow PDF format.

https\://pages.vaadin.com/en/build-a-modern-web-app-with-spring-boot-vaadin-pdf

`render-banner.ts`

```html
export class RenderBanner extends HTMLElement {
  connectedCallback() {
    this.renderBanner();
  }

  renderBanner() {
    let bannerWrapper = document.getElementById('tocBanner');

    if (bannerWrapper) {
      return;
    }

    let tocEl = document.getElementById('toc');

    // Add an empty ToC div in case page doesn't have one.
    if (!tocEl) {
      const pageTitle = document.querySelector(
        'main > article > header[class^=PageHeader-module--pageHeader]'
      );
      tocEl = document.createElement('div');
      tocEl.classList.add('toc');

      pageTitle?.insertAdjacentElement('afterend', tocEl);
    }

    // Prepare banner container
    bannerWrapper = document.createElement('div');
    bannerWrapper.id = 'tocBanner';
    tocEl?.appendChild(bannerWrapper);

    // Banner elements
    const text = document.querySelector('.toc-banner-source-text')?.innerHTML;
    const link = document.querySelector('.toc-banner-source-link')?.textContent;

    const bannerHtml = `<div class='toc-banner'>
          <a href='${link}'>
            <div class="toc-banner--img"></div>
            <div class='toc-banner--content'>${text}</div>
          </a>
        </div>`;

    bannerWrapper.innerHTML = bannerHtml;

    // Add banner image
    const imgSource = document.querySelector('.toc-banner-source .image');
    const imgTarget = bannerWrapper.querySelector('.toc-banner--img');

    if (imgSource && imgTarget) {
      imgTarget.appendChild(imgSource);
    }
  }
}
```

<!-- vale Vaadin.OneSentencePerLine = YES --><!-- vale Vale.Spelling = YES --><!-- vale Vale.Terms = YES -->

`BE63AD5C-9B5F-46D3-B7A3-2AB0DAA07361`
