Create A Full-Stack Java App Using Hilla

Create A Full-Stack Java App Using Hilla


5 min read

I've recently come across Hilla, probably on Twitter, and decided to have a play around with it and find out what it does.

This article will serve as an introduction to Hilla.

Let's start.

What is Hilla?

Hilla is a web framework that uses Java Spring Boot for the backend, Lit library and Typescript for the frontend.

If you'd like to know more, I wrote an article on my blog about the Spring Boot Architecture.

Spring Boot is a Java backend framework that uses the Spring Framework internally.

Spring Boot makes it easier to bootstrap an application, and it's best used to create [REST APIs](Link.

Lit library instead

Lit is a simple library for building fast, lightweight web components. At Lit's core is a boilerplate-killing component base class that provides reactive state, scoped styles, and a declarative template system that's tiny, fast and expressive.

I'm a backend engineer, so I had to inform myself about the definition of a web component.

According to :

Web components are a set of web platform APIs that allow you to create new custom, reusable, encapsulated HTML tags to use in web pages and web apps.

A web component allows you to separate an application into smaller and reusable pieces.

Typescript is a programming language created and maintained by Microsoft.

Typescript is:

  • strongly-typed.
  • supports object-oriented programming.
  • supports compilation.

Hilla allows you to build small and large enterprise-level applications.

Hilla has three main characteristics:

  1. Type-safety: Hilla makes Java endpoints safe.

  2. UI components: you won't have to create UI components yourself.

  3. Speed and flexibility: Hilla uses Lit, a lightweight framework which helps you create components quickly and efficiently.

You can access Hilla's official documentation here.

1. Environment Setup

If you (like me) have never used the Typescript ecosystem, you may have to do a few more installations than the one suggested in Hilla's Documentation.

You will need:

  • Node 16.14 or higher.
  • Vaadin.
  • Lit.
  • Typescript.

To install NodeJs, follow the official page.


To install the Vaadin CLI (a command-line interface to create Java web applications), run this command in your terminal:

npm i -g @vaadin/cli

To install Lit, run this command in your terminal:

npm i lit

To install Typescript, run this command in your terminal:

npm i -g typescript

2. Create the App via the Terminal

To create a Hilla application, run this command in your terminal:

npx @vaadin/cli init --preset hilla-quickstart-tutorial hilla-student-app

It may or may not ask you to install @vaadin/cli. If so, type y.

Import the project into your IDE.

3. Create the Model Class

Let's create a file under the src/main/java/com/example/application directory.

The model class represents a Student object with a name, surname, and age.

package com.example.application;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

public class Student {

    private String name;

    private String surname;

    @Min(value = 18)
    private int age;

    public String getName() {
        return name;

    public void setName(String name) { = name;

    public String getSurname() {
        return surname;

    public void setSurname(String surname) {
        this.surname = surname;

    public int getAge() {
        return age;

    public void setAge(int age) {
        this.age = age;


4. Create a Student Endpoint Class

In backend engineering, an "endpoint" typically corresponds to a URL. It's the point that allows communication with another program.

Hilla guarantees type-safe access to the server.

package com.example.application;

import com.vaadin.flow.server.auth.AnonymousAllowed;
import dev.hilla.Endpoint;
import dev.hilla.Nonnull;

import java.util.ArrayList;
import java.util.List;

public class StudentEndpoint {

    private final List<Student> studentList = new ArrayList<>();

    public @Nonnull List<@Nonnull Student> getStudents()    {
        return studentList;

    public Student saveStudent(Student student) {
        return student;

Note that the class has two annotations:

  • @endpoint: this annotation makes the class accessible to the client.
  • @anonymousallowed: anyone can access this endpoint.

5. Create a Reactive UI in Typescript

In the frontend/views/student/student-view.ts path, there should be a studentview.ts file. If not, create one and paste the following code:

import '@vaadin/button';
import '@vaadin/text-field';
import '@vaadin/number-field';
import '@vaadin/grid/vaadin-grid';
import { html } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { View } from '../../views/view';
import { Binder, field } from '@hilla/form';
import { getStudents, saveStudent } from 'Frontend/generated/StudentEndpoint';
import Student from 'Frontend/generated/com/example/application/Student';
import StudentModel from 'Frontend/generated/com/example/application/StudentModel';

export class StudentView extends View {

  private students: Student[] = [];
  private binder = new Binder(this, StudentModel);

  render() {
    return html`
          <div class="padding: 25px">

            <h3>Student List</h3>
            <vaadin-grid .items="${this.students}" theme="row-stripes" style="max-width: 400px">
              <vaadin-grid-column path="name"></vaadin-grid-column>
              <vaadin-grid-column path="surname"></vaadin-grid-column>
              <vaadin-grid-column path="age"></vaadin-grid-column>

      async addStudent() {
        const students = await this.binder.submitTo(saveStudent);
        if (students) {
          this.students = [...this.students, students];

        async firstUpdated() {
          const students = await getStudents();
          this.students = students;


Note how this class has a couple of annotations:

  • @customElement: this annotation registers the class (student-view) with the browser.

  • @state: the students' list is marked with @state because it's subject to change.

6. Run the Application

Next, run the application.

It should automatically open in the browser, and you should see an app like this:


Add a name, surname, and age.

Then click the Add button.


Notice that you're not allowed to add a student whose age is under 18:


When you run the application, you might get something such as:

Port XXXX is already in use.

To fix this:

  • Go into the resources folder and open file.

  • Change the server.port=${PORT:XXXX} into another port. For example, if the error says that the port 8080 is already in use, change it to 8082 (or 8083, 8585, etc.).


In this tutorial, you learned how to create a basic Hilla application.

I hope you've found it helpful.

I'm learning Typescript from scratch, so let me know if you've spotted anything incorrect in the comments.

Until next time! ๐Ÿ™‹๐Ÿพโ€โ™€๏ธ


Did you find this article valuable?

Support Maddy by becoming a sponsor. Any amount is appreciated!