# How to Organize Assets and Static Files in Go Web Applications

> Organize Go web application assets and static files effectively using the golang-standards project layout convention. Streamline your project structure for better maintainability and clarity.

- Repository: [golang-standards/project-layout](https://github.com/golang-standards/project-layout)
- Tags: how-to-guide
- Published: 2026-03-06

---

**Use the `golang-standards/project-layout` convention by placing runtime static files in `/web/static`, HTML templates in `/web/template`, compiled front-end bundles in `/web/app`, and repository assets like logos in `/assets` to maintain clean separation between Go source code and web resources.**

Organizing assets and static files in Go web applications requires a deliberate directory structure that keeps web resources accessible to your HTTP server without cluttering your Go source tree. The **golang-standards/project-layout** repository defines community-standard conventions for positioning these files outside `cmd/`, `pkg/`, and `internal/` while supporting both filesystem-based development and embedded production binaries. Following this layout ensures your application can switch between `http.FileServer` serving and Go 1.16+ `embed` directives without changing directory paths or application logic.

## Standard Directory Structure for Web Assets

The project-layout specification establishes four distinct locations for different asset types, each serving a specific purpose in the development and deployment lifecycle.

### /web/static for HTTP Server Assets

Place CSS, JavaScript, images, fonts, and other files that your application serves directly to clients into **`/web/static`**. This directory functions as the document root for your HTTP handlers and remains logically isolated from your Go packages, making it easy to cache via CDN or reverse proxy. The repository includes a placeholder at `/web/static/.keep` to signal this directory should exist in version control even when empty.

### /web/template for Server-Side Rendering

Store HTML templates and partials used with `text/template` or `html/template` in **`/web/template`**. This separation allows you to parse template sets using `template.ParseFS` or `template.ParseGlob` without traversing unrelated static assets. The placeholder file `/web/template/.keep` marks this location for version control.

### /web/app for Compiled Front-End Bundles

Single-page applications (SPAs) and other compiled JavaScript artifacts belong in **`/web/app`**. This directory holds production builds from React, Vue, or Angular projects that your Go backend serves as static content, distinguishing compiled output from raw source files in `/web/static`.

### /assets for Repository Resources

Use the top-level **`/assets`** directory for files that support the repository itself but never serve over HTTP, such as README screenshots, documentation diagrams, and CI badges. As documented in [`/assets/README.md`](https://github.com/golang-standards/project-layout/blob/main//assets/README.md), these resources exist for presentation and build tooling rather than runtime web serving.

## Development and Production Serving Strategies

Go web applications support two primary patterns for delivering assets. The project-layout structure accommodates both without requiring directory reorganization.

### Serving from the Filesystem During Development

For local development, serve assets directly from disk to enable rapid iteration without recompiling your binary. Use `http.FileServer` combined with `http.StripPrefix` to map URL paths to your `web/static` directory:

```go
package main

import (
	"net/http"
)

func main() {
	// Serve everything under /web/static at the URL path /static/
	fs := http.FileServer(http.Dir("./web/static"))
	http.Handle("/static/", http.StripPrefix("/static/", fs))

	http.ListenAndServe(":8080", nil)
}

```

With this configuration, a file located at [`web/static/css/style.css`](https://github.com/golang-standards/project-layout/blob/main/web/static/css/style.css) becomes accessible at `http://localhost:8080/static/css/style.css`.

### Embedding Assets for Single-Binary Deployment

With Go 1.16+, embed the entire `web/static` and `web/template` trees directly into your executable using the `//go:embed` directive. This approach produces a single distributable file while preserving the logical directory structure:

```go
package main

import (
	"embed"
	"io/fs"
	"net/http"
)

//go:embed web/static/*
//go:embed web/template/*
var embeddedFS embed.FS

func main() {
	// Create an http.FileSystem from the embedded static files
	sub, _ := fs.Sub(embeddedFS, "web/static")
	staticFS := http.FileServer(http.FS(sub))

	http.Handle("/static/", http.StripPrefix("/static/", staticFS))

	// Load templates from the embedded filesystem
	// tmpl, _ := template.ParseFS(embeddedFS, "web/template/*.html")

	http.ListenAndServe(":8080", nil)
}

```

The `fs.Sub` function isolates the `web/static` subtree so URL paths remain consistent between development and embedded modes. Templates parse directly from `embeddedFS` using `template.ParseFS` without extracting files to disk.

### Accessing Repository Assets at Build Time

Assets stored in `/assets` require standard file system operations since they remain outside the embedded web tree. Access these during build processes or documentation generation:

```go
// Example: reading a logo for inclusion in a generated PDF
data, err := os.ReadFile("assets/logo.png")
if err != nil {
    log.Fatal(err)
}
_ = data // use the binary data as needed

```

## Key Implementation Files

The project-layout repository includes specific documentation and placeholders that establish this structure:

- **[`/assets/README.md`](https://github.com/golang-standards/project-layout/blob/main//assets/README.md)** – Explains the distinction between repository assets and runtime web files.
- **`/web/static/.keep`** – Preserves the static directory in version control.
- **`/web/template/.keep`** – Placeholder for server-side template storage.
- **`/web/app/.keep`** – Indicates the location for SPA build artifacts.
- **[`/web/README.md`](https://github.com/golang-standards/project-layout/blob/main//web/README.md)** – Provides overview documentation for the web resource hierarchy.

## Summary

- Place HTTP-servable static files in **`/web/static`** and keep server-side templates in **`/web/template`** to maintain separation from Go source code.
- Store repository-specific assets like documentation images in **`/assets`**, intentionally excluding them from runtime web serving.
- Use **`/web/app`** for compiled front-end bundles such as React or Vue SPA artifacts.
- Serve files directly from disk during development using **`http.FileServer`** and **`http.StripPrefix`** for rapid iteration.
- Embed assets into your binary using **`//go:embed`** directives and **`embed.FS`** for single-executable deployments in production.
- Reference the **[`/web/README.md`](https://github.com/golang-standards/project-layout/blob/main//web/README.md)** and placeholder files in the `golang-standards/project-layout` repository to ensure your structure aligns with Go community standards.

## Frequently Asked Questions

### What is the difference between /assets and /web/static?

The **`/assets`** directory contains repository-level files like README screenshots and documentation images that support the project presentation but never serve over HTTP. In contrast, **`/web/static`** holds runtime assets such as CSS, JavaScript, and images that your Go application serves directly to clients via `http.FileServer` or embeds into the binary.

### How do I serve embedded static files with the correct URL prefix?

Use **`fs.Sub`** to extract the specific subdirectory from your `embed.FS` before passing it to `http.FileServer`. For example, `fs.Sub(embeddedFS, "web/static")` isolates the static content, allowing you to strip the `/static/` prefix with `http.StripPrefix` so that [`web/static/css/style.css`](https://github.com/golang-standards/project-layout/blob/main/web/static/css/style.css) maps correctly to [`/static/css/style.css`](https://github.com/golang-standards/project-layout/blob/main//static/css/style.css) in the browser.

### Can I use this layout with a React or Vue single-page application?

Yes, place your compiled SPA bundle files in **`/web/app`** as designated by the project-layout standard. Configure your Go server to serve the [`index.html`](https://github.com/golang-standards/project-layout/blob/main/index.html) and static artifacts from this directory, or move the built assets into `/web/static` if you prefer serving them alongside other static files using the same `http.FileServer` handler.

### Where should HTML templates be stored in a Go web project?

Store HTML templates and partials in **`/web/template`**, a dedicated location separate from static assets. This allows you to parse templates efficiently using `template.ParseFS` when embedding or `template.ParseGlob` when serving from disk, maintaining clean organization between your presentation logic and style resources.