Skip to content
The fastest web framework in V language (vlang)
V HTML JavaScript
Branch: master
Clone or download

Latest commit

Latest commit 10aa073 Jan 27, 2020


Type Name Latest commit message Commit time
Failed to load latest commit information.
example improve static file serve Dec 24, 2019
.gitignore template finish Dec 14, 2019
LICENSE Initial commit Dec 9, 2019 Update Jan 27, 2020
_config.yml Set theme jekyll-theme-slate Dec 17, 2019 update todo Dec 16, 2019
valval.v Update valval.v Jan 26, 2020
valval_test.v template finish Dec 14, 2019


Valval is the fastest web framework in V language.

This means you can develop a website quickly and run it even faster!

A simple demo:
import valval

fn hello(req valval.Request) valval.Response {
	return valval.response_ok('hello world')

fn main() {
	mut app := valval.new_app(true)
	app.register('/', hello)
	valval.runserver(app, 8012)


Install V language

$ git clone
$ cd v
$ make

Install OpenSSL

$ brew install openssl

$ sudo apt install libssl-dev openssl ca-certificates

Windows (Win10 Verified): Source can be downloaded from:

You can find a Graphic installer if that's more to you're liking.

Or use V in docker, it includes OpenSSL

docker run -it -p 8012:8012 --name vlang taojy123/vlang bash

Install Valval

Using Git

$ git clone
$ ln -s $(pwd)/valval ~/.vmodules/valval 

Using VPM

Watchman123456 has registered the module with vpm. Simply use the following if you have v on your PATH variable:

$ v install watchman123456.valval

Note: If you use vpm; you'll have to change the import to:

import watchman123456.valval

As well as the usage to watchman123456.valval


A Minimal Application

A minimal Valval application looks something like this:

// demo.v

module main

import valval

fn hello(req valval.Request) valval.Response {
	return valval.response_ok('hello world')

fn main() {
	mut app := valval.new_app(true)
	app.register('/', hello)
	valval.runserver(app, 8012)

Run server

$ v run demo.v

Then you can visit to see the website

$ curl
hello world

Debug Mode

You can decide whether to use debug mode when calling valval.new_app()

mut app := valval.new_app(true)  // debug mode
mut app := valval.new_app(false) // production mode

debug mode will print out more infomation while app running

Service Port

You can decide the service port number when calling the valval.runserver()

valval.runserver(app, 8012)  // listening 8012 port
valval.runserver(app, 80)    // listening 80 port

The valval server will bind address, so you can visit the website by or ServerIp:Port


Use the App.register() function to band a handler function to request path

The handler function should have a parameter of type Request and return a Response

mut app := valval.new_app(true)

app.register('/', hello)   		         //

app.register('/users', function1)        //
app.register('/user/info', function2)    //

app.register('POST:/book', function3)  // by POST
app.register('DELETE:/book', function4)    // by DELETE
app.register('/book', function5)         // by other methods

app.register('*', function6)   		     // all remain

valval.runserver(app, 80)

Accessing Request Data

Currently, only the following data can be parsed:

  • query parameters by GET request; by valval.Request.query[xxx]
  • x-www-form-urlencoded parameters by POST / PUT / PATCH request; by valval.Request.form[xxx]
fn hello(req valval.Request) valval.Response {
	mut name = request.query['name']
	if name == '' {
		name = 'world'
	return valval.response_ok('hello $name')

fn post_hello(req valval.Request) valval.Response {
	mut name = request.form['name']
	if name == '' {
		name = 'world'
	return valval.response_ok('hello $name')

app.register('GET:/hello', hello)
app.register('POST:/hello', post_hello)

valval.Request.get() provides a quick way to get data whether it is from query or form.

fn hello(req valval.Request) valval.Response {
	name = request.get('name', 'world')  // default: 'world'
	return valval.response_ok('hello $name')

app.register('/hello', hello)

More types of request data will be supported in the future:

  • parameters in url
  • multipart/form-data by POST request
  • application/json by POST request
  • uploaded files

Static Files

Use valval.App.serve_static to serve local files

mut app := valval.new_app(true)

app.serve_static('/static/', './relative/path/to/static/')  
// visit ...

app.serve_static('/static2/', '/absolute/path/to/static2/') 
// visit ...

valval.runserver(app, 80)

Rendering Templates

Valval used a whole new idea to implement the template function; inspired by Vue's system.

Has the following advantages:

  • You don't need to spend time learning how to use templates, if you have used Vue before.
  • If you haven't used Vue, you also can learn it fast, because it's so easy.
  • It can integrate some commonly used UI frameworks, such as: element, mint, vant, antd, bootstrap...
  • I don't need to spend time developing built-in templates 😁.

An example for template:


import (

struct User {
	name string
	age int
	sex bool

fn users(req valval.Request) valval.Response {

	// create a view by template file (`test6.html` can be a relative or absolute path)
	// use `element` ( as ui framework
	mut view := valval.new_view(req, 'users.html', 'element') or {
		return valval.response_bad(err)

	users := [
		User{'Lucy', 13, false},
		User{'Lily', 13, false},
		User{'Jim', 12, true},
	msg := 'This is a page of three user'

	// use view.set to bind data for rendering template
	// the second parameter must be a json string
	view.set('users', json.encode(users))
	view.set('msg', json.encode(msg))

	return valval.response_view(view)


        <title>Users Page</title>
        <!-- Content in body can use template syntax -->
        <p v-for="u in users">
            <span>{{}}</span> ,
            <span>{{u.age}}</span> ,
            <el-tag v-if="">Male</el-tag>
            <el-tag v-else>Female</el-tag>


Use valval.response_redirect() to generate a redirect response

fn test1(req valval.Request) valval.Response {
	name = req.get('name', '')
	if name == '' {
		return valval.response_redirect('/not_found')
	return valval.response_ok('hello $name')


In addition to the responses mentioned above (response_ok, response_view, response_redirect)

Valval also provides other response types, as follows:

struct User {
	name string
	age int
	sex bool

fn text(req valval.Request) valval.Response {
	return valval.response_text('this is plain text response')

fn json(req valval.Request) valval.Response {
	user = User{'Tom', 12, true}
	return valval.response_json(user)
	// -> {"name": "Tom", "age": 12, "sex": true}

fn json_str(req valval.Request) valval.Response {
	user = User{'Tom', 12, true}
	user_str = json.encode(user)
	return valval.response_json_str(user_str)
	// -> {"name": "Tom", "age": 12, "sex": true}

fn file(req valval.Request) valval.Response {
	return valval.response_file('path/to/local/file')

fn bad(req valval.Request) valval.Response {
	return valval.response_bad('Parameter error!')
	// response with statu code 400

Complete Example

API Reference


  • valval.new_app(debug bool) App
  • valval.runserver(app App, port int)
  • valval.new_view(req Request, template string, ui string) ?View
  • valval.response_ok(content string) Response
  • valval.response_text(content string) Response
  • valval.response_json(obj T) Response
  • valval.response_json_str(data string) Response
  • valval.response_file(path string) Response
  • valval.response_redirect(url string) Response
  • valval.response_bad(msg string) Response
  • valval.response_view(view View) Response


valval.Request {

​ pub:

​ app App

​ method string

​ path string

​ query map[string]string

​ form map[string]string

​ body string

​ headers map[string]string


  • fn (req Request) get(key string, default_value string) string
  • fn (req Request) is_api() bool
  • fn (req Request) is_page() bool

valval.Response {

​ pub mut:

​ status int = 200

​ body string = ''

​ content_type string = 'text/html; charset=utf-8'

​ headers map[string]string


  • fn (res mut Response) set_header(key string, value string)

valval.View {

​ req Request

​ template string

​ ui string = 'element'

​ mut:

​ context map[string]string

​ pub:

​ content string // html after template compiled


  • fn (view mut View) set(key string, data string)

valval.App {

​ pub:

​ name string = 'ValvalApp'

​ debug bool = true

​ run_ts int = 0

​ mut:

​ router map[string]Handler

​ static_map map[string]string


  • fn (app mut App) register(path string, func fn(Request) Response)
  • fn (app mut App) serve_static(static_prefix string, static_root string)

valval.Server {

​ pub:

​ address string = ''

​ port int = 8012

​ mut:

​ app App


  • fn (server Server) run()
You can’t perform that action at this time.