• Blog
  • Docs
  • Pricing
  • We’re hiring!
Log inSign up
chadparker

chadparker

townie-testing

Public
Like
townie-testing
Home
Code
2
serveFile.md
H
test-randomuser.ts
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 milliseconds.
Sign up now
Code
/
serveFile.md
Code
/
serveFile.md
Search
5/31/2025
Viewing readonly version of main branch: v15
View latest version
serveFile.md

serveFile() - Val Town Utility

serveFile() is a Val Town utility function that serves files from your project with proper content types and handling.

Import

Create val
import { serveFile } from "https://esm.town/v/std/utils/index.ts";

What It Does

  • Reads a file from your Val Town project
  • Returns it as an HTTP response
  • Automatically sets the correct Content-Type header based on file extension
  • Handles file not found errors gracefully

Basic Usage

Create val
import { serveFile } from "https://esm.town/v/std/utils/index.ts"; import { Hono } from "https://esm.sh/hono"; const app = new Hono(); // Serve a specific file app.get("/", (c) => serveFile("/frontend/index.html", import.meta.url)); // Serve any file in the frontend directory app.get("/frontend/*", (c) => serveFile(c.req.path, import.meta.url));

Parameters

  1. path (string) - The file path within your project (e.g., "/frontend/index.html")
  2. import.meta.url - Always pass this as the second parameter (tells the function where your project is located)

Content Type Detection

serveFile() automatically sets the correct Content-Type header:

File ExtensionContent-Type
.htmltext/html
.csstext/css
.js, .mjsapplication/javascript
.jsonapplication/json
.pngimage/png
.jpg, .jpegimage/jpeg
.svgimage/svg+xml
.txttext/plain
.pdfapplication/pdf
And many more...

Common Patterns

1. Serve Entire Directories

Create val
// Serve everything in frontend/ and shared/ app.get("/frontend/*", (c) => serveFile(c.req.path, import.meta.url)); app.get("/shared/*", (c) => serveFile(c.req.path, import.meta.url));

2. Serve Index Page with Data Injection

Create val
import { readFile } from "https://esm.town/v/std/utils/index.ts"; app.get("/", async (c) => { // Read the HTML file manually to modify it let html = await readFile("/frontend/index.html", import.meta.url); // Inject initial data to avoid extra round-trips const initialData = await fetchInitialData(); const dataScript = `<script> window.__INITIAL_DATA__ = ${JSON.stringify(initialData)}; </script>`; html = html.replace("</head>", `${dataScript}</head>`); return c.html(html); });

3. Fallback to Index for SPA Routing

Create val
app.get("*", async (c) => { // Try to serve the requested file first try { return await serveFile(c.req.path, import.meta.url); } catch { // If file doesn't exist, serve index.html (for client-side routing) return serveFile("/frontend/index.html", import.meta.url); } });

4. Serve Static Assets with Cache Headers

Create val
app.get("/assets/*", async (c) => { const response = await serveFile(c.req.path, import.meta.url); // Add cache headers for static assets response.headers.set("Cache-Control", "public, max-age=31536000"); return response; });

How It Works Internally

When you call serveFile(c.req.path, import.meta.url):

  1. Path Resolution: Uses import.meta.url to locate your project
  2. File Reading: Reads the file at the specified path
  3. Content-Type Detection: Analyzes file extension to set proper MIME type
  4. Response Creation: Returns a Response object with the file contents and headers
  5. Error Handling: Returns appropriate HTTP errors if file doesn't exist

Important Notes

  • Always use import.meta.url as the second parameter
  • File paths start with / (e.g., "/frontend/index.html", not "frontend/index.html")
  • Works with any file type that Val Town supports (text-based files)
  • Automatic error handling - returns 404 if file doesn't exist
  • No caching by default - add your own cache headers if needed

vs. Hono's serveStatic

❌ DON'T use Hono's serveStatic middleware in Val Town:

Create val
// This doesn't work in Val Town import { serveStatic } from 'https://esm.sh/hono/middleware';

✅ DO use Val Town's serveFile utility:

Create val
// This works perfectly in Val Town import { serveFile } from "https://esm.town/v/std/utils/index.ts";

Related Utilities

  • readFile() - Read file contents as a string (useful for modifying before serving)
  • listFiles() - List all files in the project
FeaturesVersion controlCode intelligenceCLIMCP
Use cases
TeamsAI agentsSlackGTM
DocsShowcaseTemplatesNewestTrendingAPI examplesNPM packages
PricingNewsletterBlogAboutCareers
We’re hiring!
Brandhi@val.townStatus
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Open Source Pledge
Terms of usePrivacy policyAbuse contact
© 2025 Val Town, Inc.