What if deploying a function was as easy as saving a file? Val Town gives you instantly deployable JavaScript functions with a built-in editor.
What is Val Town?
Val Town is a social website to write and deploy TypeScript functions. Every function (called a Val) gets its own URL. No build step, no server, no deploy process.
Types of Vals
HTTP Handler
// Automatically gets a URL: https://username-functionName.web.val.run
export default async function(req: Request): Promise<Response> {
const url = new URL(req.url);
const name = url.searchParams.get("name") || "World";
return Response.json({ message: `Hello, ${name}!` });
}
Cron Job
// Runs on a schedule
export default async function() {
const res = await fetch("https://api.example.com/health");
if (!res.ok) {
// Send alert
await email({ to: "me@example.com", subject: "API is down!" });
}
}
Email Handler
// Gets its own email address: username.valName@valtown.email
export default async function(email: Email) {
console.log(`From: ${email.from}`);
console.log(`Subject: ${email.subject}`);
console.log(`Body: ${email.text}`);
// Process the email...
}
Built-in Storage (SQLite)
import { sqlite } from "https://esm.town/v/std/sqlite";
// Create table
await sqlite.execute(`CREATE TABLE IF NOT EXISTS visits (url TEXT, count INTEGER)`);
// Insert
await sqlite.execute(`INSERT INTO visits VALUES (?, ?)`, ["/home", 1]);
// Query
const result = await sqlite.execute(`SELECT * FROM visits WHERE count > ?`, [10]);
console.log(result.rows);
Built-in Blob Storage
import { blob } from "https://esm.town/v/std/blob";
// Store data
await blob.setJSON("config", { theme: "dark", lang: "en" });
// Retrieve
const config = await blob.getJSON("config");
// Store binary
await blob.set("image.png", imageBuffer);
Real-World Examples
API Proxy
export default async function(req: Request): Promise<Response> {
const url = new URL(req.url);
const target = url.searchParams.get("url");
if (!target) return new Response("Missing url param", { status: 400 });
const response = await fetch(target);
const data = await response.json();
return Response.json(data, {
headers: { "Access-Control-Allow-Origin": "*" },
});
}
Daily Weather Email
import { email } from "https://esm.town/v/std/email";
export default async function() {
const res = await fetch("https://wttr.in/NYC?format=j1");
const weather = await res.json();
const temp = weather.current_condition[0].temp_F;
await email({
subject: `NYC Weather: ${temp}F`,
text: `Current temperature in NYC is ${temp}F`,
});
}
Val Town vs Alternatives
| Feature | Val Town | Cloudflare Workers | AWS Lambda |
|---|---|---|---|
| Deploy | Save button | wrangler deploy | SAM/CDK |
| Editor | Built-in web | Local | Local |
| SQLite | Built-in | D1 | No |
| Built-in | No | SES | |
| Cron | Built-in | Cron Triggers | EventBridge |
| Free Tier | Generous | Generous | 1M requests |
| Social | Fork/remix vals | No | No |
Need serverless data extraction? Check out my Apify actors — cloud functions for web scraping. For custom solutions, email spinov001@gmail.com.
Top comments (0)