Skip to content
On this page

Projects ​

Projects are serverless applications deployed to Web URLs. Projects in Netzo are programmed using Deno, a simple, modern and secure runtime for JavaScript and TypeScript. In essence, a project consist of collections of static files that are automatically hosted by netzo. Each Project is deployed to its own unique URL and ran globally at the network edge when an HTTP Request is made to its URL. netzo/lib can be used within projects to make coding projects even simpler.

Projects

Listen to HTTP requests

Note that to make a project invokable at its edge URL, its entrypoint must register an HTTP server to listen to and respond to incoming HTTP requests. Otherwise, a project can still be used as a module to export code meant to be imported imported by other projects via their URL.

Creating Projects ​

  1. Head over to the Projects page within a Workspace and click the Create button.

  2. Give a unique name for the project and select a starting template. We'll select the basic TypeScript example for now.

  3. Add the necessary environment variables in the drawer to the right.

Project URLs ​

Projects can be invoked via HTTP requests to any of:

  • Production URL: https://{uid}.netzo.io
  • Preview URL: https://{deploymentId}.netzo.io

Project UID

The project uid MUST be globally unique, between 3-42 characters and contain only lowercase letters a-z, numbers 1-9 and hyphens -. You can change it in Project > Settings > General.

Deployments are booted on first request, not on deployment

Note that deploying a Project will save its latest changes but won't actually boot the new deployment until invoking it for the first time. Due to this, the first request after deployment could take a bit longer, following requests should be almost instant.

CORS Headers ​

To be able to invoke a Project from the browser, you'll need to enable CORS. By default, CORS headers will be set to * unless you specify otherwise in the Response headers.

HeaderDescriptionDefault
access-control-allow-origina space-separated list of origins allowed to access the resource*
access-control-allow-methodsa comma-separated list of HTTP methods allowed to access the resource*
access-control-allow-headersa comma-separated list of HTTP headers allowed to access the resource*

WARNING

If overwriting the default of * for access-control-allow-origin, include "https://app.netzo.io" as allowed origin to be able to invoke the project from within Netzo, otherwise the request will be blocked by the browser automatically due to CORS.

For example, to allow all origins, methods and headers for the Project:

typescript
serve((_req: Request): Response => new Response("Hello World!"));
serve((_req: Request): Response => new Response("Hello World!"));

To allow only a specific origin, method or header you can overwrite the defaults of * individually or all at once as follows:

typescript
serve((_req: Request): Response => new Response("Hello World!", {
  headers: {
    "access-control-allow-origin": "https://app.netzo.io",
    "access-control-allow-methods": "GET, POST",
    "access-control-allow-headers": "x-foo, x-bar"
  }
}));
serve((_req: Request): Response => new Response("Hello World!", {
  headers: {
    "access-control-allow-origin": "https://app.netzo.io",
    "access-control-allow-methods": "GET, POST",
    "access-control-allow-headers": "x-foo, x-bar"
  }
}));

Modules ​

Modules are reusable code bundles distributed via URLs. Netzo makes it easy to author and deploy Modules on the click of a button. Modules can be private or public, in which case they can be imported by third-party scripts (without authentication).

  • import allows you to include and use local or remote modules in your code.
  • export allows you to expose code to be imported by other modules.

Module resolution

Deno adopts browser-like module resolution, meaning that file names must be specified in full. File extensions are are used to serve file contents with the appropriate Content-Type header. If no Content-Type header is present, it will be resolved based on its extension. For example, a file named foo.ts will be served with Content-Type: application/typescript.

No special treatment for index.(ts|js)

Deno encourages using mod.(ts|js) as the module entry point, as there is no special handling for index.(ts|js) paths. This is to avoid the common practice of importing files by ommiting the index.(ts|js) filename (common in Node.js), which goes against web URL semantics.

Import Maps ​

Import maps allows control over what URLs get fetched by import statements and import() expressions. They can be thought of as shortcuts to map short and memorable aliases to (longer) import URLs. Deno will resolve imports based on an import_map.json file.

json
{
  "imports": {
    "netzo/": "https://deno.land/netzo/"
  }
}
{
  "imports": {
    "netzo/": "https://deno.land/netzo/"
  }
}

The location of the import_map.json file can be set via the importMap field of deno.json. By default, this is the root of the Deno module.

Hosting ​

Netzo will automatically host all your modules under https://api.netzo.io/deployments/{id}/{...path} with path being a valid file path including etension (e.g. components/Table.tsx). Files will be served with their corresponding Content-Type header by Netzo, for example text/html for .html files.

Module best practices

For simpler modules it is recommended to have a single mod.(ts|js) file at the module entry point. When modularizing a larger module, it adviced to keep the mod.(ts|js) entry point as lean as possible (using only import/export statements), keeping business logic in other files.

Publishing ​

Modules can also be published to the Deno ecosystem via the official https://deno.land/x hosting service. It caches releases of open source modules and serves them at one easy to remember domain. Navigate to their official docs to learn more.

Runtime Environment ​

Runtime APIs ​

The following Web and Deno APIs are supported on the runtime.

  • addEventListener
  • Cache
  • Durable Objects
  • Encoding
  • Fetch
  • FetchEvent
  • Headers
  • HTMLRewriter
  • KV
  • Request
  • Response
  • ScheduledEvent
  • Streams
  • Web Crypto
  • Web standards
  • WebSockets
  • eval()
  • new Function()

INFO

To learn more, you can always head over to the Deno documentation

(Virtual) Filesystem ​

Projects have access to a read-only virtual filesystem that is scoped to the Project's files and mounted at file:///src/. Reading outside of the project root is not allowed.

Netzo supports a limited set of the file system APIs available in Deno. These file system APIs can access static files from your deployments.

The APIs that are available are:

  • Deno.cwd returns the current working directory of your deployment.
  • Deno.readDir allows listing the contents of a directory.
  • Deno.readFile allows reading a file into memory.
  • Deno.readTextFile allows reading a file into memory (decoded as UTF-8 string).
  • Deno.open allows opening a file, returning a file handle
  • Deno.stat reads a file system entry's metadata.
  • Deno.lstat reads a file system entry's metadata (without following symlinks).
  • Deno.realPath reads a file system entry's metadata (without following symlinks).
  • Deno.readLink returns the target path for a symlink.

Absolute file paths must be passed as a URL object

On unix "file:///..." is treated as a relative path, therefore absolute file paths must be passed as a URL object new URL("file:///...") instead of a string "file:///...".

For example, a file example.txt at the project root can be read in multiple ways:

typescript
await Deno.readTextFile("example.txt");
await Deno.readTextFile("./example.txt");
await Deno.readTextFile("/src/example.txt");
await Deno.readTextFile("file:///src/example.txt"); // ❌ throws error
await Deno.readTextFile(new URL("file:///src/example.txt"));
await Deno.readTextFile("example.txt");
await Deno.readTextFile("./example.txt");
await Deno.readTextFile("/src/example.txt");
await Deno.readTextFile("file:///src/example.txt"); // ❌ throws error
await Deno.readTextFile(new URL("file:///src/example.txt"));

Refer to the Deno documentation for more information.

Import Assertions for JSON modules

Note that .json files can be imported via import assertions with the assert keyword:

typescript
import data from "./data.json" assert { type: "json" };
import data from "./data.json" assert { type: "json" };

This is equivalent to reading the file and parsing it as JSON:

typescript
const data = JSON.parse(await Deno.readTextFile("./data.json"));
const data = JSON.parse(await Deno.readTextFile("./data.json"));

Regions ​

Netzo deploys projects globally to the edge. Each new Request is served from the closest region to the client making the request. The following regions are available:

    1. Taiwan: asia-east1
    1. Hong Kong: asia-east2
    1. Tokyo: asia-northeast1
    1. Osaka: asia-northeast2
    1. Seoul: asia-northeast3
    1. Mumbai: asia-south1
    1. Delhi: asia-south2
    1. Singapore: asia-southeast1
    1. Jakarta: asia-southeast2
    1. Sydney: australia-southeast1
    1. Melbourne: australia-southeast2
    1. Warsaw: europe-central2
    1. Finland: europe-north1
    1. Belgium: europe-west1
    1. London: europe-west2
    1. Frankfurt: europe-west3
    1. Netherlands: europe-west4
    1. Zurich: europe-west6
    1. Milan: europe-west8
    1. Paris: europe-west9
    1. Tel Aviv: me-west1
    1. Madrid: europe-southwest1
    1. MontrΓ©al: northamerica-northeast1
    1. Toronto: northamerica-northeast2
    1. SΓ£o Paulo: southamerica-east1
    1. Chile: southamerica-west1
    1. Iowa: us-central1
    1. South Carolina: us-east1
    1. North Virginia: us-east4
    1. Ohio: us-east5
    1. Texas: us-south1
    1. Oregon: us-west1
    1. California: us-west2
    1. Utah: us-west3
    1. Nevada: us-west4

This list will be updated as new regions are added.