FeaturesTemplatesShowcaseTownie
AI
BlogDocsPricing
Log inSign up
neverstew
neverstewtanstackReactHonoExample
Remix of laurynas/tanstackReactHonoExample
Public
Like
tanstackReactHonoExample
Home
Code
6
backend
3
frontend
7
shared
2
.vtignore
README.md
deno.json
Branches
1
Pull requests
Remixes
History
Environment variables
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in miliseconds.
Sign up now
Code
/
README.md
Code
/
README.md
Search
…
README.md

React + TanStack + Hono Val Town Project

Full-stack message board built for Val Town.

Tech Stack

Backend

  • Hono web framework
  • Drizzle ORM with SQLite
  • Deno runtime

Frontend

  • React 19
  • TanStack Router (code-first routing)
  • TanStack Query (server state management)
  • Tailwind CSS
  • TypeScript

Features

  • Message board with persistent storage
  • Client-side routing
  • Optimistic updates
  • Server-side data injection
  • Type-safe database operations

Project Structure

├── backend/          # Hono server running on Val Town
│   ├── database/     # Drizzle schema, migrations, and queries
│   └── index.ts      # Main Hono application
├── frontend/         # React app running in browser
│   ├── components/   # React components
│   ├── lib/          # Utilities and hooks
│   └── router.tsx    # TanStack Router configuration
└── shared/           # Code shared between frontend and backend

API Endpoints

  • GET / - Serves the React application with initial data
  • GET /api/messages - Fetch all messages (JSON)
  • POST /api/messages - Create a new message
  • GET /public/** - Static assets (CSS, JS, etc.)
  • /* - All other routes handled by TanStack Router

Val Town Constraints

  • Read-only filesystem after deployment
  • ESM imports via esm.sh for npm packages
  • Code-first routing (no file-based routing)

Implementation

Router

Create val
const homeRoute = new Route({ getParentRoute: () => rootRoute, path: "/", component: () => <App {...window.__INITIAL_DATA__} /> });

Query

Create val
export function usePostMessage() { return useMutation({ mutationFn: (content: string) => postMessage(content), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["messages"] }); }, }); }

Schema

Create val
export const messages = sqliteTable("messages", { id: integer("id").primaryKey({ autoIncrement: true }), content: text("content").notNull(), timestamp: text("timestamp").notNull().default(new Date().toISOString()), });
Go to top
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Product
FeaturesPricing
Developers
DocsStatusAPI ExamplesNPM Package Examples
Explore
ShowcaseTemplatesNewest ValsTrending ValsNewsletter
Company
AboutBlogCareersBrandhi@val.town
Terms of usePrivacy policyAbuse contact
© 2025 Val Town, Inc.