Ktor 2.3.1 Help

Serving static content

Whether we're creating a website or an HTTP endpoint, many applications need to serve files (such as stylesheets, scripts, images, etc.). While it is certainly possible with Ktor to load the contents of a file and send it in response to a request, given this is such a common functionality, Ktor simplifies the entire process for us with the static 1 and 2 plugins.

The first step is to define where we want the content to be served from:

  • Folders - describes how to serve static files from a local filesystem. In this case, relative paths are resolved using the current working directory.

  • Embedded application resources - describes how to serve static files from the classpath.


routing { staticFiles("/static", File("files")) }

This maps any request to /static to the files physical folder in a current working directory. In this case, Ktor recursively serves up any file from files as long as a URL path and physical filename match.

Serving resources

routing { staticResources("/static", "assets") }

This maps any request to /static to the assets package in application resources. In this case, Ktor recursively serves up any file from assets package as long as a URL path and path to resource match.

Additional configuration

Ktor provides more configurations to static files and resources.

Define an index file

We can also define the default file to be loaded when the directory is requested. By default, index file name is index.html, you can set custom one using index parameter:

routing { staticFiles("/static", File("files"), index = "my_index.html") }
routing { staticResources("/static", "assets", index = "my_index.html") }

In this case, for requests to /static/path/to/dir a Ktor server serves files/path/to/dir/my_index.html for files and assets/path/to/dir/my_index.html for resources.

Pre-compressed files

Ability to serve pre-compressed files and avoid using dynamic compression.

routing { staticFiles("/static", File("files")) { preCompressed(CompressedFileType.BROTLI, CompressedFileType.GZIP) } }
routing { staticResources("/static", "assets") { preCompressed(CompressedFileType.BROTLI, CompressedFileType.GZIP) } }

In this example, for a request made to /static/script.js, Ktor can serve js/script.js.br or js/script.js.gz.

HEAD requests

Ability to automatically responds to a HEAD request for every path inside static route that has a GET defined.

routing { staticFiles("/static", File("files")) { enableAutoHeadResponse() } }
routing { staticResources("/static", "assets") { enableAutoHeadResponse() } }

Default file

Ability to reply with default file for any request inside static route, that has no corresponding file

routing { staticFiles("/static", File("files")) { default("/path/to/default/file") } }
routing { staticResources("/static", "assets") { default("/path/to/default/file") } }

Content type

By default, Ktor tries to guess value of Content-Type header from a file extension.

routing { staticFiles("/static", File("files")) { contentType { file -> when (file.name) { "index.txt" -> ContentType.Text.Html else -> null } } } }
routing { staticResources("/static", "assets") { contentType { url -> when (url.file) { "index.txt" -> ContentType.Text.Html else -> null } } } }

In this example, response for file index.txt will have Content-Type: text/html header and apply default behaviour for every other file.

Caching headers

Ktor can add Caching headers for static files.

routing { staticFiles("/static", File("files")) { cacheControl { file -> when (file.name) { "index.txt" -> listOf(Immutable, CacheControl.MaxAge(10000)) else -> emptyList() } } } }
routing { staticResources("/static", "assets") { cacheControl { url -> when (url.file) { "index.txt" -> listOf(Immutable, CacheControl.MaxAge(10000)) else -> emptyList() } } } }

Excluding files

Ktor can exclude some files and respond with 403 Forbidden status code when such files are requested.

routing { staticFiles("/static", File("files")) { exclude { file -> file.path.contains("secret_file") } } }
routing { staticResources("/static", "assets") { exclude { url -> url.path.contains("secret_file") } } }

File extensions fallbacks

When a requested file is not found, Ktor can add the given extensions to the file name and search for it.

routing { staticFiles("/static", File("files")) { extensions("html", "htm") } }
routing { staticResources("/static", "assets") { extensions("html", "htm") } }

In this example, when /static/index is requested, ktor will serve index.html content.

Custom modifications

Ktor can apply custom modification to a resulting response.

routing { staticFiles("/static", File("files")) { modify { file, call -> call.response.headers.append(HttpHeaders.ETag, calculateEtag(file)) } } }
routing { staticResources("/static", "assets") { modify { url, call -> call.response.headers.append(HttpHeaders.ETag, calculateEtag(file)) } } }

Handle errors

If the requested content is not found, Ktor will automatically respond with a 404 Not Found HTTP status code. For more information about personalizing error handling, see Status Pages.


You can find the full examples here:

Last modified: 19 April 2023