DEV Community

Alex Spinov
Alex Spinov

Posted on

Val Town Has Free Cloud Functions — Here's How to Run JavaScript in the Cloud Without a Server

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}!` });
}
Enter fullscreen mode Exit fullscreen mode

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!" });
  }
}
Enter fullscreen mode Exit fullscreen mode

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...
}
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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": "*" },
  });
}
Enter fullscreen mode Exit fullscreen mode

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`,
  });
}
Enter fullscreen mode Exit fullscreen mode

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
Email 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)