Home Documentation Templates Examples Showcase GitHub ↗
Theme

Pattern

Full web applications.

Nift can be the frontend composition/build layer in a full application without trying to replace your backend runtime, API framework, database layer, package manager or browser framework. The boundary is simply files and HTTP.

Think in responsibilities, not branded stacks.

Nift can own templates, partials, tracked pages and browser-facing paths. Everything else can stay with the tool that already does it well.

A general shape

app/
  content/              # page-specific HTML/content
  templates/            # shared document templates + partials
  public/               # generated pages + browser assets
  frontend/             # optional TS/React/Vue/Svelte/Vite source
  server/               # Go / Node / Python / C++ / ...
  .nift/
  package.json          # optional frontend tooling
  Makefile              # optional orchestration

The exact directories are yours. Nift only needs its configured content/output locations and tracking metadata.

Nift + vanilla JavaScript + Go

This is one of the cleanest full-stack combinations: Nift generates the pages, ordinary browser JavaScript consumes a Go API, and the Go service handles runtime state.

app/
  content/
    index.html
    dashboard.html
  templates/
    template.html
    partials/nav.html
  public/
    assets/app.js
    assets/site.css
  server/
    main.go
    api/
  .nift/
<link rel="stylesheet" href="@pathto('public/assets/site.css')">
@input('templates/partials/nav.html')
<main>@content</main>
<script type="module" src="@pathto('public/assets/app.js')"></script>
const res = await fetch('/api/status');
const status = await res.json();
document.querySelector('#status').textContent = status.message;
http.Handle("/", http.FileServer(http.Dir("public")))
http.HandleFunc("/api/status", func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    io.WriteString(w, `{"message":"online"}`)
})

Nothing requires a Nift-specific Go package. The generated frontend and HTTP API simply meet at the browser.

Nift + TypeScript + Vite + Go

As browser code grows, TypeScript/Vite can own bundling while Nift continues to own the HTML shell and page composition.

frontend/
  src/app.ts
  vite.config.ts
public/
  assets/app.js
content/
templates/
server/
// vite.config.ts (conceptual)
export default defineConfig({
  build: {
    outDir: '../public/assets',
    emptyOutDir: false
  }
});
npm run build:frontend
nift build
# then run/build the Go server

Nift + React island + Go API

React can own a state-heavy part of a page while Nift emits the rest as direct HTML.

<section class="account-intro">
  <h1>Account</h1>
  <p>Static/helpful surrounding content stays plain HTML.</p>
</section>
<div id="account-app"></div>
<script type="module" src="@pathto('public/assets/account.js')"></script>
// React entry point produced by your normal bundler
createRoot(document.getElementById('account-app')).render(<AccountApp />);

This avoids requiring React to own every page just because one region benefits from it.

Nift + Vue or Svelte

The pattern is identical. Vite produces a browser entry point, and a Nift-generated page provides the mount point.

<div id="pricing-calculator"></div>
<script type="module" src="@pathto('public/assets/pricing-calculator.js')"></script>

Whether that bundle was produced by Vue, Svelte, React or vanilla TypeScript is deliberately outside Nift's concern.

Nift + Node + Express

Express can serve the generated public directory and expose APIs beside it.

import express from 'express';

const app = express();
app.use(express.json());
app.use(express.static('public'));

app.get('/api/health', (req, res) => {
  res.json({ ok: true });
});

app.listen(3000);
{
  "scripts": {
    "build:site": "nift build-all",
    "build:client": "vite build",
    "build": "npm run build:client && npm run build:site",
    "start": "node server.js"
  }
}

Nift + Bun + TypeScript server

Bun can be both the package/tooling runtime and the backend runtime while Nift remains the HTML build layer.

bun run build:client
nift build
bun run server.ts

No special adaptation is necessary: use Bun normally and point it (or a reverse proxy) at public/.

Nift + Python + FastAPI

from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles

app = FastAPI()

@app.get('/api/health')
def health():
    return {'ok': True}

app.mount('/', StaticFiles(directory='public', html=True), name='public')

Flask or another Python framework can use the same arrangement. Django projects can also keep Nift-built static/frontend output separate from Django's runtime concerns if that fits the application.

Nift + Python API + React/Vue/Svelte frontend island

Nift               Vite/framework       FastAPI/Flask
----               --------------       -------------
page shell     +    interactive JS   +  API routes
navigation          rich state          auth/business logic
content pages       client widgets      database access
paths/assets        bundling             background jobs

This is often a useful separation for internal tools and dashboards: Nift handles the stable information architecture while the framework handles the stateful parts.

Nift + server-rendered backend routes

Nift does not have to generate every response your server returns. You can use it for static/documentation/marketing/help/account-shell pages while the backend renders or returns genuinely dynamic routes itself.

/                    Nift-built page
/docs/*              Nift-built pages
/help/*              Nift-built pages
/app                  server route / SPA shell
/api/*                backend JSON API
/auth/*               backend authentication flow

Nift + WebSockets / realtime applications

Realtime behaviour is also just browser/runtime behaviour. Nift can generate the shell and JavaScript reference; your backend owns the socket connection.

const socket = new WebSocket('wss://example.com/ws');
socket.addEventListener('message', event => {
  const data = JSON.parse(event.data);
  updateDashboard(data);
});

This can back terminals, telemetry displays, live dashboards, collaborative tools or other realtime interfaces without changing Nift's role.

Nift + Tailwind

Tailwind can scan the HTML/templates and generate CSS into public/assets/. Nift simply references that file.

npx @tailwindcss/cli -i ./frontend/styles.css -o ./public/assets/site.css
nift build
<link rel="stylesheet" href="@pathto('public/assets/site.css')">

Nift + an external build orchestrator

For a larger repository, let a Makefile, task runner, package script or CI system define the order of operations.

build:
\tnpm run build:frontend
\tnift build-all
\tgo build -o bin/server ./server

Nift does not need a plugin system merely to participate in a build graph.

Development workflow

terminal 1:  nift build-auto 0.5
terminal 2:  npm run dev        # if using Vite/etc.
terminal 3:  go run ./server    # or node/python/bun/etc.

You can keep each tool's normal development workflow. If you prefer one command, wrap them in your existing task runner.

Production workflow

npm run build:frontend   # optional
nift build-all
go build ./server        # or node/python/bun build/deploy steps

Then deploy public/ with the backend, upload it to a CDN/object store, or serve it independently—whatever fits the architecture.

What Nift is not trying to own

Runtime state

Sessions, databases, authentication, queues and business logic belong in your backend/runtime stack.

Component runtime

If React/Vue/Svelte is useful, use it normally. Nift does not need its own imitation of those frameworks.

Package ecosystem

npm, Bun and other package managers remain available without being wrapped in Nift-specific packages.

Specialist asset tooling

Vite, esbuild, Rollup, minifiers, Tailwind, Sass and image tools can write directly into the project/public pipeline.

Nift provides the glue without trying to become the universe.

A full application can be sophisticated without Nift itself becoming complicated. The point is to let Nift's small build/template model compose cleanly with whatever architecture the application actually needs.