Getting Started

A complete Hello World in three files. JWeb is a Spring Boot library — add one dependency and write pages in pure Java. No frontend toolchain, no templates, no build step.

1. Add the Dependency

Maven — the JitPack repository plus the dependency:

<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
</repositories>

<dependency>
    <groupId>com.github.oscar-osmig</groupId>
    <artifactId>Jweb</artifactId>
    <version>v1.0.6</version>
</dependency>

Gradle:

repositories { maven { url 'https://jitpack.io' } }
dependencies { implementation 'com.github.oscar-osmig:Jweb:v1.0.6' }
Requires Java 21+. Spring Boot's web starter arrives transitively — you don't add it yourself.

2. Project Structure

Three files. Java allows one public class per file, so each of these is its own file — putting them in one file will not compile:

src/main/java/org/example/
    App.java              <- starts the application
    Routes.java           <- maps URLs to pages
    pages/
        HomePage.java     <- the page itself

3. App.java

@JWebApplication replaces @SpringBootApplication. Framework beans arrive through auto-configuration, so only your own package is scanned.

package org.example;

import com.osmig.Jweb.framework.JWebApplication;
import org.springframework.boot.SpringApplication;

@JWebApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

4. Routes.java

A @Component implementing JWebRoutes. Page routes render a Template; router routes take the request and can return anything.

package org.example;

import com.osmig.Jweb.framework.JWeb;
import com.osmig.Jweb.framework.JWebRoutes;
import com.osmig.Jweb.framework.middleware.Middlewares;
import org.example.pages.HomePage;
import org.springframework.stereotype.Component;

@Component
public class Routes implements JWebRoutes {
    @Override
    public void configure(JWeb app) {
        app.use(Middlewares.recommended());   // security headers, request ids

        app.pages("/", HomePage.class);
        app.get("/hello", req -> "Hello from JWeb");
    }
}

5. pages/HomePage.java

A page is any class implementing Template. Elements come from El, styles from the CSS DSL — both fully type-checked.

package org.example.pages;

import com.osmig.Jweb.framework.core.Element;
import com.osmig.Jweb.framework.template.Template;

import static com.osmig.Jweb.framework.elements.El.*;
import static com.osmig.Jweb.framework.styles.CSS.*;
import static com.osmig.Jweb.framework.styles.CSSUnits.*;
import static com.osmig.Jweb.framework.styles.CSSColors.*;

public class HomePage implements Template {
    @Override
    public Element render() {
        return div(style().maxWidth(px(700)).margin(zero, auto).padding(rem(3)),
            h1(style().fontSize(rem(2)).fontWeight(700), text("Welcome")),
            p(style().color(hex("#64748b")), text("Your first JWeb page."))
        );
    }
}
Watch your IDE's auto-import: div, h1, p and text must all come from the single El.* import above. If it offers javax.management.Query.div or com.mongodb.client.model.Indexes.text, reject it — those compile but are not JWeb.

6. Run It

mvn spring-boot:run

#  /       -> your page
#  /hello  -> Hello from JWeb
Default port is 8080 — set server.port in application.properties or application.yaml to change it.

Next: a Shared Layout (optional)

Once you have more than one page, a layout gives them a common shell. It is a Template that takes the page content:

public class MainLayout implements Template {
    private final Element content;
    public MainLayout(Element content) { this.content = content; }

    @Override
    public Element render() {
        return html(
            head(metaCharset(), metaViewport(), title("My App")),
            body(nav(a(href("/"), text("Home"))), main(content))
        );
    }
}

// in Routes.configure:
app.layout(MainLayout.class)
   .pages("/", HomePage.class,
          "/about", AboutPage.class);

Configuration (optional)

Everything has a working default — set only what you need:

server:
  port: 8080

jweb:
  dev:
    debug: false          # stack traces on error pages (dev only)

  data:                   # MongoDB, off by default
    enabled: false

  ai:                     # built-in AI, off by default
    enabled: false
    api-key: ${AI_API_KEY:}
Keep secrets in environment variables (${AI_API_KEY:}) so they never reach your repository or a published jar.

Skip the Setup

The CLI generates this whole structure, wired and ready to run:

jweb new myapp --package=com.mycompany.myapp
cd myapp && mvn spring-boot:run
Next: Elements for the HTML DSL, Styling for CSS, Fragments for server-driven UI without writing JavaScript.