vibe.d beta banner
get vibe.d
0.10.1

Asynchronous I/O that doesn’t get in your way, written in D

Documentation

First steps

First, install the DUB package manager to let it handle downloading and building of vibe.d and derived applications. On non-Windows systems, a number of additional dependencies needs to be installed. See the project description on GitHub for details.

Manual building (e.g. using RDMD) is a possible alternative, but you have to make sure that external libraries are linked in (such as OpenSSL) and that the import directories for all sub projects of vibe.d (such as vibe-core and vibe-http) are properly set. You can run DUB with the -v switch to see the actual compiler command line if in doubt.

The easiest way to get started is to run the following command from your projects directory:

cd /path/to/my/projects
dub init <project-name> -t vibe.d

This will create a new directory with the given name and creates the basic directory structure that is recommended for vibe.d projects. Running it will start up an HTTP server on port 8080, serving a simple plain-text page. As the next step, you can go ahead and edit the source/app.d file. If you want to publish your project, you should also edit the dub.json/dub.sdl file and properly fill in all fields, including a "license" field.

Once you have the project in place, simply run DUB from the project's root directory and it will get all dependencies, compile the application, and run it:

cd path/to/project
dub
    Starting Performing "debug" build using ldc2 for x86_64.
  Up-to-date diet-ng 1.8.1: building configuration [library]
  Up-to-date taggedalgebraic 0.11.22: building configuration [library]
  Up-to-date eventcore 0.9.28: building configuration [winapi]
  Up-to-date vibe-container 1.3.0: building configuration [library]
  Up-to-date vibe-core 2.8.2: building configuration [winapi]
  Up-to-date vibe-inet:textfilter 1.0.0: building configuration [library]
  Up-to-date vibe-serialization 1.0.1: building configuration [library]
  Up-to-date vibe-stream 1.1.0: building configuration [library]
  Up-to-date vibe-inet 1.0.0: building configuration [library]
  Up-to-date mir-linux-kernel 1.0.1: building configuration [library]
  Up-to-date vibe-inet:crypto 1.0.0: building configuration [library]
  Up-to-date vibe-stream:tls 1.1.0: target for configuration [openssl-3.0] is up to date.
  Up-to-date vibe-http 1.0.0: building configuration [library]
  Up-to-date vibe-d:mail 0.10.0: building configuration [library]
  Up-to-date vibe-d:mongodb 0.10.0: building configuration [library]
  Up-to-date vibe-d:redis 0.10.0: building configuration [library]
  Up-to-date vibe-d:utils 0.10.0: building configuration [library]
  Up-to-date vibe-d:web 0.10.0: building configuration [library]
  Up-to-date vibe-d 0.10.0: building configuration [library]
    Building vibe-test ~master: building configuration [application]
     Linking vibe-test
    Finished To force a rebuild of up-to-date targets, run again with --force
             Copying files for vibe-stream:tls...
     Running vibe-test.exe
[main(----) INF] Listening for requests on http://[::1]:8080/
[main(----) INF] Listening for requests on http://127.0.0.1:8080/
[main(----) INF] Please open http://127.0.0.1:8080/ in your browser.

Recommended project structure

The recommended directory structure for a project, which the "dub init" command establishes, is separated into three base folders:

appname/
	source/
		app.d
	public/
		images/
		styles/
			style.css
	views/
		layout.dt
		index.dt
	dub.sdl
Example structure of a web application project

For a simple web application, the 'app.d' file could look similar to this one:

import vibe.vibe;

void index(HTTPServerRequest req, HTTPServerResponse res)
{
	res.render!("index.dt", req);
}

void main()
{
	auto router = new URLRouter;
	router.get("/", &index);
	
	auto settings = new HTTPServerSettings;
	settings.port = 8080;
	
	listenHTTP(settings, router);
	
	runApplication();
}
Simple app.d file with minimal routing

The 'views' sub folder is automatically searched for templates instantiated with render. The two templates in the example structure might look like this:

doctype html
html
	head
		title Example page
	body
		block body
Example layout.dt
extends layout

block body
	h1 Example page - Home
	p Hello, World!
Example index.dt

This structure makes use of the blocks/extensions feature of the Diet template compiler. For more advanced template features see the Diet template documentation.

Finally, the "dub.sdl" (SDLang) lets the vibe.d package manager automatically download and compile dependency libraries. This file will also provide the description that is needed to later put your own library into the public extension registry.

name "appname"
description "My fabulous new app"
copyright "Copyright (C) 2000 Me. All rights reserved."
license "AGPL-3.0"
homepage "http://appname.org"
authors "Hans Wurst"
dependency "vibe-d" version="~>0.10.0"
Example dub.sdl

DUB also provides support for the original JSON based syntax. The filename to use is "dub.json" in this case:

{
	"name": "appname",
	"description": "My fabulous new app",
	"copyright": "Copyright (C) 2000 Me. All rights reserved.",
	"license": "AGPL-3.0",
	"homepage": "http://appname.org",
	"authors": ["Hans Wurst"],
	"dependencies": {
		"vibe-d": "~>0.10.0"
	}
}
Example dub.json

Example projects

A library of example projects is maintained in the Git repository. Most things not covered in this document can be found there in the form of code: Example projects

To run the examples locally, you can either download the repository as a zip file, or use GIT to get the examples:

git clone https://github.com/vibe-d/vibe.d.git

To run the "http_server" example, type:

dub run --root=vibe.d/examples/http_server

HTTP

Server configuration

The HTTP server supports a number of configuration options to customize its behavior. By default, the server will listen on all local network adapters on port 80 and will perform complete request parsing. The following list gives an overview of the most common settings:

port
The port on which the HTTP server shall listen
bindAddresses
A list of all interfaces on which the server shall listen. IPv4 and IPv6 addresses, as well as domain names are supported.
options
Controls optional features of the web server. Certain options can be disabled to increase speed or to decrease memory usage. By default, the following options are enabled: parseURL, parseQueryString, parseFormBody, parseJsonBody, parseMultiPartBody, parseCookies. Enabled options are ORed together.
errorPageHandler
Provides a way to customize error pages. For example:
void errorPage(HTTPServerRequest req,
	HTTPServerResponse res,
	HTTPServerErrorInfo error)
{
	res.render!("error.dt", req, error);
}

void main()
{
	auto settings = new HTTPServerSettings;
	settings.errorPageHandler = toDelegate(&errorPage);
	// ...
}
Inside of the error.dt template, the variables req, code and msg are available in this example.
tlsContext
Lets the server operate as an HTTPS server. You should probably also set the port to 443 in case this field is set.

HTTPS

To serve HTTPS connections, the configuration simply needs to have a TLS context that has the appropriate certificate and private key files set:

auto settings = new HTTPServerSettings;
settings.port = 443;
settings.bindAddresses = ["127.0.0.1"];
settings.tlsContext = createTLSContext(TLSContextKind.server);
settings.tlsContext.useCertificateChainFile("server-cert.pem");
settings.tlsContext.usePrivateKeyFile("server-key.pem");

Selecting the TLS provider

Two TLS providers are currently supported, OpenSSL and the D port of Botan. By default, OpenSSL 3.x is used to provide TLS/HTTPS functionality. To select a different provider, or to avoid compiling with TLS support enabled, the appropriate build configuration of the vibe-d:tls sub package needs to be selected:

dependency "vibe-stream:tls" version="~>1.0"
subConfiguration "vibe-stream:tls" "botan"

When using a JSON based package recipe, the two lines have to be inserted as follows (the "…" are just placeholders for other possible directives):

{
	…
	"dependencies": {
		…
		"vibe-stream:tls": "~>1.0"
	},
	"subConfigurations": {
		…
		"vibe-stream:tls": "botan"
	}
}

Available configurations:

"notls"
Don't compile with TLS support
"openssl"
OpenSSL, auto-detect version (default)
"openssl-3.0"
OpenSSL 3.0.x (default in Windows)
"openssl-1.1"
OpenSSL 1.1.x
"openssl-1.0"
OpenSSL 1.0.x
"openssl-static"
Uses the openssl-static package to provide static OpenSSL 3.x binaries on various platforms
"botan"
D port of Botan

Routing

The URLRouter class provides a convenient way to let different functions handle different URLs. It supports static path matching, variable placeholders and wild-cards. Any matched variable will be available as an entry in the params dictionary.

In addition to the path, the HTTP method is also used for matching requests. Each HTTP method has a corresponding method in the code.prettyprint URLRouter class (e.g. get or post). The following example will route all GET requests matching the path scheme "/users/*" to the userInfo handler and serve all other GET requests using the files in the public folder, see serveStaticFiles.

import vibe.vibe;

void userInfo(HTTPServerRequest req, HTTPServerResponse res)
{
	auto username = req.params["user"];
	render!("userinfo.dt", username)(res);
}

void addUser(HTTPServerRequest req, HTTPServerResponse res)
{
	enforceHTTP("user" in req.form, HTTPStatus.badRequest, "Missing user field.");
	res.redirect("/users/"~req.form["user"]);
}

void main()
{
	auto router = new URLRouter;
	router.get("/users/:user", &userInfo);
	router.post("/adduser", &addUser);
	router.get("*", serveStaticFiles("./public/"));
	
	// To reduce code redundancy, you can also
	// use method chaining:
	router
		.get("/users/:user", &userInfo)
		.post("/adduser", &addUser)
		.get("*", serveStaticFiles("./public/"));
		
	listenHTTP(new HTTPServerSettings, router);
	
	runApplication();
}
Example: GET/POST routing and static file serving

Diet templates

Vibe.d supports HTML templates with a syntax mostly compatible to Pug templates. They provide a concise way to dynamically generate the HTML code of the final web pages. D expressions and statements can be embedded and the full vibe.d API is available within templates.

Templates should reside somewhere inside the 'views' folder of a project. They are then rendered using the render function, which takes the template file name as the first template argument, followed by a list of variables that should be available to the template. Finally, it takes a HTTPServerResponse to render into.

The following example shows a number of features of the Diet template compiler. A full reference of the template syntax is found on the Diet templates page.

doctype html
html
	head
		title My page: #{pageTitle}
	body
		h1= pageTitle
		p This is the content of this page. The
			| title "#{pageTitle}" is inserted dynamically.
			| We can also use loops and other D statements:
		block placeholder
		p
			- foreach(i, ch; pageTitle)
				| #{i+1}. character: #{ch}
		p.special.small This paragraph has the 'special'
			| and 'small' CSS classes
		p#footer This paragraph has the id 'footer'.
		#somediv.
			I'm a multiline text
			inside the div #somediv
Example: Template file with dynamic code inserts and several other template features

Error pages

There are three ways in which an error page is sent back to the client:

  • An exception is thrown from the request handler or while parsing the request. By default, a 500 "Internal Server Error" is returned. By throwing a HTTPStatusException , the status code can be customized.
  • The request handler does not write a response. In this case the server automatically returns a 404 "Not Found" error.
  • The request handler manually sets an error status to HTTPServerResponse.statusCode and writes a body. In this case, the error page will be written exactly as specified.

The HTTPServerSettings can be used to provide a custom error page handler. If one is provided, it is called for any of the first two conditions and must render an error page to the response object. If no handler is given, a simple plain-text error page is generated. See the HTTP server configuration section for an example.

Authentication

Currently, HTTP-Basic-Auth and HTTP-Digest-Auth authentication methods are implemented. Higher level mechanisms such as OAuth will be provided using extension libraries.

A simple way to plug authentication into a web application is to use the fall-through feature of the URLRouter. If the user is properly authenticated, the performBasicAuth function will not do anything and the URLRouter will continue to match the request to all following routes. If, however, there is no authentication or if the username/password pair is not valid, it will throw a HTTPStatusException exception which generates a 403 error page so that the user is prompted with a password dialog on the browser side. The routing stops in this case.

Note that it is generally recommended to make use of the high level web framework when developing web application front ends. See the "web" example project for a way to implement session based authentication in such a setting.

import vibe.vibe;

bool checkPassword(string user, string password)
{
	return user == "admin" && password == "secret";
}

void main()
{
	auto router = new URLRouter;
	// the following two routes are accessible without authentication:
	router.get("/", staticTemplate!"index.dt");
	router.get("/about", staticTemplate!"about.dt");
	
	// now any request is matched and checked for authentication:
	router.any("*", performBasicAuth("Site Realm", toDelegate(&checkPassword)));
	
	// the following routes can only be reached if authenticated:
	router.get("/profile", staticTemplate!"profile.dt");
	router.get("/internal", staticTemplate!"internal.dt");
	
	// ...
}
Example: Using HTTP-Basic-Auth to restrict access

Sessions

Cookie based HTTP sessions are supported directly by the HTTP server. To be able to use them, you first have to set a SessionStore in the HTTPServerSettings . Sessions are then established by calling code.prettyprint.lang-d HTTPServerResponse.startSession and stopped using code.prettyprint.lang-d HTTPServerResponse.terminateSession. The returned Session object behaves as a key value store taking strings as keys and values.

import vibe.vibe;

void login(HTTPServerRequest req, HTTPServerResponse res)
{
	enforceHTTP("username" in req.form && "password" in req.form,
		HTTPStatus.badRequest, "Missing username/password field.");
		
	// todo: verify user/password here
	
	auto session = res.startSession();
	session.set("username", req.form["username"]);
	session.set("password", req.form["password"]);
	res.redirect("/home");
}

void logout(HTTPServerRequest req, HTTPServerResponse res)
{
	if (res.session) res.terminateSession();
	res.redirect("/");
}

void checkLogin(HTTPServerRequest req, HTTPServerResponse res)
{
	// force a redirect to / for unauthenticated users
	if (!req.session)
		res.redirect("/");
}

void main()
{
	auto router = new URLRouter;
	router.get("/", staticTemplate!"index.dt");
	router.post("/login", &login);
	router.post("/logout", &logout);
	// restrict all following routes to authenticated users:
	router.any("*", &checkLogin);
	router.get("/home", staticTemplate!"home.dt");
	
	auto settings = new HTTPServerSettings;
	settings.sessionStore = new MemorySessionStore;
	// ...
}
Example: Using a HTTP session for user authentication

Client requests

Client request are done using the requestHTTP function.

import vibe.vibe;

void main()
{
	requestHTTP("http://google.com",
		(scope HTTPClientRequest req) {
			// could add headers here before sending,
			// write a POST body, or do similar things.
		},
		(scope HTTPClientResponse res) {
			logInfo("Response: %s", res.bodyReader.readAllUTF8());
		}
	);
}
Example: Performing a simple HTTP request

Note that you can leave off the explicit `HTTPClientRequest` and `HTTPClientResponse` parameter types. They will be inferred automatically by the compiler.

A connection pool is used internally in conjunction with persistent HTTP connections (keep-alive) for maximum thoughput.

Web framework

Based on the low-level HTTP/HTML foundation, the high-level web application framework allows for faster and more solid web application development. It uses a class based declarative approach to avoid the boilerplate code that would otherwise usually be needed. Static typing is exploited as much as possible to avoid conversion errors, or errors accessing wrong runtime keys (such as a non-existent or mistyped form field).

The framework comes in two flavors, one for front end development, targeted at generating HTML pages and processing form requests, and one for REST based back end development, providing a transparent JSON/REST based RPC mechanism (client and server). Both of these components share the same basis and use the same approach to map class methods to routes of the URLRouter.

For the usual case, both, the HTTP method and the matching path are inferred from the class method's name. In particular, the name is mapped to a certain HTTP method according to its prefix and the rest of the name is converted to a path name in a configurable style. On top of that, it is possible to use the @path and @method attributes to override these defaults.

HTTP methodCorresponding prefixes
GETget, query, getter @property methods, methods named index
POSTpost, create, add, no prefix
PUTput, set, setter @property methods
PATCHpatch, update
DELETEdelete, erase, remove

Web interface generator

The front end web interface generator automatically maps incoming query or POST form fields to method parameters, performing the necessary conversion and validation automatically. On top of that, it offers several convenience functions for rendering Diet templates, handling sessions and performing redirects - without directly accessing the underlying HTTPServerRequest or HTTPServerResponse object. This enables a completely statically checked and clean code style in most cases.

For those situations where more control is required, it is possible to simply declare parameters of type HTTPServerRequest or HTTPServerResponse to give a method full access. Note that this is in contrast to the REST interface generator covered below, which cannot give access to the request/response without losing the ability to generate the client side of the REST protocol. It does, however, provide a way to get around this, using the @before attribute.

import vibe.http.router;
import vibe.http.server;
import vibe.web.web;

void main()
{
	auto router = new URLRouter;
	router.registerWebInterface(new WebInterface);
	
	auto settings = new HTTPServerSettings;
	settings.port = 8080;
	settings.sessionStore = new MemorySessionStore;
	listenHTTP(settings, router);
}

class WebInterface {
	private {
		// stored in the session store
		SessionVar!(bool, "authenticated") ms_authenticated;
	}
	
	// GET /
	void index()
	{
		bool authenticated = ms_authenticated;
		render!("index.dt", authenticated);
	}
	
	// POST /login (username and password are automatically read as form fields)
	void postLogin(string username, string password)
	{
		enforceHTTP(username == "user" && password == "secret",
			HTTPStatus.forbidden, "Invalid user name or password.");
		ms_authenticated = true;
		redirect("/");
	}
	
	// POST /logout
	@method(HTTPMethod.POST) @path("logout")
	void postLogout()
	{
		ms_authenticated = false;
		terminateSession();
		redirect("/");
	}
}
Example: source/app.d
doctype 5
html
	head
		title Welcome
	body
		h1 Welcome
		
		- if (authenticated)
			form(action="logout", method="POST")
				button(type="submit") Log out
		- else
			h2 Log in
			form(action="login", method="POST")
				p User name:
					input(type="text", name="username")
				p Password:
					input(type="password", name="password")
				button(type="submit")
Example: views/index.dt

Localization

Using GNU gettext compatible .po translation files, it's possible to localize Diet templates at compile time. This just requires putting the translation files with the naming scheme <name>.<language>.po into a path that is registered in the "stringImportPaths" field of the dub.json. <language> must be a language identifier of the form en_US.

import vibe.web.web;

struct TranslationContext {
	alias languages = TypeTuple!("en_US", "de_DE");
	mixin translationModule!"example";
}

@translationContext!TranslationContext
class WebInterface {
	void index()
	{
		render!("index.dt");
	}
}
Example: source/app.d
doctype 5
html
	head
		title& Welcome
	body
		h1& Welcome
		
		p& home.welcome.text
Example: views/index.dt
msgid "Welcome"
msgstr "Welcome"

msgid "home.welcome-text"
msgstr "Hello, this is a translation example."
Example: translations/example.en_US.po
msgid "Welcome"
msgstr "Willkommen"

msgid "home.welcome-text"
msgstr "Hallo, dies ist ein Übersetzungs-Beispiel."
Example: translations/example.de_DE.po

REST interface generator

Similar to the browser oriented web interface generator, there is a machine communication oriented JSON/REST based interface generator. Method parameters are mapped to JSON fields and get serialized according to the usual serialization rules. In addition to the interface generator, there is also a client generator, which automatically implements a class that emits the proper REST calls to access the REST interface.

import vibe.core.core;
import vibe.core.log;
import vibe.http.router;
import vibe.http.server;
import vibe.web.rest;

struct Weather {
	string text;
	double temperature; // °C
}

interface MyAPI {
	// GET /weather -> responds {"text": "...", "temperature": ...}
	Weather getWeather();
	
	// PUT /location -> accepts {"location": "..."}
	@property void location(string location);
	
	// GET /location -> responds "..."
	@property string location();
}

class MyAPIImplementation : MyAPI {
	private {
		string m_location;
	}
	
	Weather getWeather() { return Weather("sunny", 25); }
	
	@property void location(string location) { m_location = location; }
	@property string location() { return m_location; }
}

void main()
{
	auto router = new URLRouter;
	router.registerRestInterface(new MyAPIImplementation);
	
	auto settings = new HTTPServerSettings;
	settings.port = 8080;
	listenHTTP(settings, router);
	
	// create a client to talk to the API implementation over the REST interface
	runTask({
		auto client = new RestInterfaceClient!MyAPI("http://127.0.0.1:8080/");
		auto weather = client.getWeather();
		logInfo("Weather: %s, %s °C", weather.text, weather.temperature);
		client.location = "Paris";
		logInfo("Location: %s", client.location);
	});
	
	runApplication();
}

Database support

MongoDB

A native MongoDB driver is part of the distribution supporting the standard set of database operations. Data is exchanged using the Bson struct.

For an comprehensive documentation of MongoDB's operations see the MongoDB manual. The API reference contains the documentation for the driver.

import vibe.vibe;

void main()
{
	MongoClient client = connectMongoDB("127.0.0.1");
	
	auto coll = client.getCollection("test.collection");
	
	foreach (doc; coll.find(["name": "Peter"]))
		logInfo("Found entry: %s", doc.toJson());
}
Example: Finding entries in a MongoDB

Redis

A client for the structured storage server Redis is included in vibe.d. Commands and operations on Redis data types are implemented as instance methods of the client and of the RedisDatabase class. The methods are named after their corresponding Redis command documented in the command reference.

On top of the low level interface, two high level modules, types and idioms are available to solve common tasks in a more convenient and type safe way. In addition to that, a Redis based HTTP session store is also included.

Raw TCP

Low level TCP connections are handled using the TCPConnection class, which implements the ConnectionStream interface. Connections can be established by either listening on a specific port for incoming connections or by actively connecting to a remote server.

Server

Listening for TCP connections is done using the listenTCP function. An implementation of a very simple echo server could look like this:

import vibe.vibe;

void main()
{
	listenTCP(7, (conn) { conn.write(conn) });
	runApplication();
}

Calling listenTCP like this will listen on all local network devices. To listen only on a specific device, the bind address can be given as an additional parameter:

import vibe.vibe;

void main()
{
	listenTCP(7, conn => conn.write(conn), "127.0.0.1");
	runApplication();
}

The address can be given as either an IPv4 or an IPv6 address string.

Client

Connecting to a TCP server is done with the connectTCP function. The following example gets the current time using the Daytime Protocol.

import vibe.vibe;

void main()
{
	auto conn = connectTCP("time-c.nist.gov", 13);
	logInfo("The time is: %s", conn.readAllUTF8());
}

Raw UDP

In addition to stream based TCP connections, packet based UDP communication is also supported. To open a UDP socket, use the listenUDP function with the appropriate port. It will return a UDPConnection instance, which can then be used to send and receive individual packets.

import vibe.appmain;
import vibe.core.core;
import vibe.core.log;
import vibe.core.net;

import core.time;


void main()
{
	runTask({
		auto udp_listener = listenUDP(1234);
		while (true) {
			auto pack = udp_listener.recv();
			logInfo("Got packet: %s", cast(string)pack);
		}
	});
	
	runTask({
		auto udp_sender = listenUDP(0);
		udp_sender.connect("127.0.0.1", 1234);
		while (true) {
			sleep(dur!"msecs"(500));
			logInfo("Sending packet...");
			udp_sender.send(cast(ubyte[])"Hello, World!");
		}
	});
	
	runApplication();
}
Example: Simple UDP based communication on localhost

Advanced topics

Publishing on the DUB registry

The DUB registry contains packages that use the same package management as vibe.d. Many of them extend and supplement vibe.d's functionality. The packages are automatically downloaded if the corresponding entry in the "dependencies" section of the project's dub.json file is present.

If you have written an extension library yourself, you can register it in the DUB registry so others can easily make use of it. For this to work, you will first have to write a proper dub.json, which has to reside in the root directory of your project (the project should adhere to the structure mentioned in the first steps). The project currently also has to be hosted either on GitHub or on BitBucket. See https://code.dlang.org/publish for more information.

{
	"name": "vibelog",
	"description": "A light-weight embeddable blog implementation",
	"homepage": "https://github.com/rejectedsoftware/vibelog",
	"license": "AGPL-3.0",
	"authors": [
		"Sönke Ludwig"
	],
	"dependencies": {
		"vibe-d": "~>0.10.0"
	}
}
Example: A dub.json file suitable for registration as a DUB package.

You can then register your project on code.dlang.org and as soon as you then add a new git tag with the name matching the current version prefixed with "v" ("v0.0.1" for the example here), it should appear there. Note that the update can take up to 30 minutes. Anyone can then add an entry similar to the following to their project to make use of the library:

{
	...
	"dependencies": {
		"vibelog": ">=0.0.1"
	}
}
Example: Corresponding dependency to use the published DUB package.

The main function

To simplify development of server-like applications that are command line based and run an event loop, vibe.d includes a default application entry point (main()). To use it, define the version VibeDefaultMain when building the project. This can be done by simply adding the following entry to your package description file: "versions": ["VibeDefaultMain"]. However, note that for new applications it is recommended to define a regular `main` function instead and call runApplication to initialize and run the vibe.d event loop.

When writing a pure command line client application, maybe something like wget, it may not be desirable to start an explicit event loop, but instead exit right after the work is done. In this case, vibe.d will automatically run a temporary event loop as long as any blocking operation is in progress, so that no explicit runApplication or runEventLoop calls are necessary.

import vibe.vibe;

void main()
{
	// ... perform setup here ...
	runApplication();
}
Example: Simple custom main function that runs an event loop.
import vibe.vibe;

void main()
{
	auto f = openFile("test.html", FileMode.CreateTrunc);
	f.write(download("http://google.com/"));
}
Example: Client application that downloads a document

Privilege lowering

For server applications it may be desirable to start the application as root so that it can listen on privileged ports or open system log files for writing. After these setup tasks, such applications impose a security risk because a hole in the application that allows to somehow execute malicious commands on the server will give the attacker full access to the system. For this reason vibe.d supports privilege lowering, where the user id and group id of the process are changed to an unprivileged user after the startup process, right before the event loop is started.

Privilege lowering can be configured in the configuration file /etc/vibe/vibe.conf (on Windows vibe.conf must be in the application's root directory instead). The two fields "user" and "group" have to be set to the the name or numeric ID of the unprivileged user/group.

{
	"user": "www-data",
	"group": "www-data"
}
Example vibe.conf file

Selecting the event loop driver

By default, the native API for each platform is selected as the default for providing the asynchronous I/O and concurrency primitive support. However, you may select a particular implementation if there are more than one available for the target platform. In order to override the default, add a sub configuration directive to your dub.sdl (choosing the "select" driver in this case):

dependency "eventcore" version="*"
subConfiguration "eventcore" "select"

When using a JSON based package recipe, the two lines have to be inserted as follows (the "…" are just placeholders for other possible directives):

{
	…
	"dependencies": {
		…
		"eventcore": "*"
	},
	"subConfigurations": {
		…
		"eventcore": "select"
	}
}

The following implementations are available:

"epoll"
Uses the Linux epoll interface, default when building for Linux, including Android
"epoll-gaia"
Uses the Linux epoll interface and getaddrinfo_a for asynchronous DNS lookups
"cfrunloop"
On Darwin based systems (macOS/iOS), uses CFRunLoop in order to be compatible with GUI applications, default on macOS and iOS
"kqueue"
Uses the BSD kqueue interface, default on FreeBSD, also available on Darwin based systems
"winapi"
Windows API based implementation using MsgWaitForMultipleObjectsEx in order to be compatible with GUI applications, default on Windows
"select"
Available for all Posix compliant systems, as well as Windows, uses select() for non-blocking I/O, only recommended for otherwise unsupported platforms
"libasync"
Uses the libasync library to choose and wrap the operating system specific API
"generic"
Does not provide a driver, but instead requires calling setupEventDriver to set a custom driver implementation

Compile time configuration

There is a number of features that can be controlled via "versions". To defined a certain version, add the corresponding entry to the "versions" in your dub.json:

{
	...
	"versions": ["VibeManualMemoryManagement", "VibeDefaultMain"],
	...
}
Declaring a "version" in dub.json
Version constantMeaning
VibeDefaultMain Tells vibe.d to use its own predefined main function. This is mutually exclusive to VibeCustomMain.
VibeDisableCommandLineParsing Disables automatic parsing of command line options passed to the application, such as "--help" or "--verbose".
VibeNoDefaultArgs Disables all default command line options, but keeps the command line argument module functional.
VibeManualMemoryManagement Performs a number of operations using manual memory management instead of the garbage collector, most notably in the HTTP server. This can lead to considerable performance improvements, but also makes certain operations unsafe and thus may open up the possibility for certain attacks. Especially any code needs to make sure to not escape any data (including string data) from HTTPServerRequest.
VibeIdleCollect Perform manual garbage collection runs when the application is idle for more than two seconds.
VibePartialAutoExit Partial workaround for issue #212 - exits the event loop after no mode file and socket based events exist. Note that this will exit the event loop, even if other kinds of events, such as timers, are still active. It is currently recommended to explicitly use exitEventLoop instead.
VibeJsonFieldNames Stores field names for JSON values for better error messages. This will use a few bytes of additional memory per Json value.
JsonLineNumbers Stores line numbers for each JSON value parsed from a JSON string for improved error messages. This will store an additional int for each Json value.
VibeOutputCompactHTML Instructs Diet-NG to output compact HTML (no extraneous white space) by default
VibeDebugCatchAll Enables catching of exceptions that derive from Error. This can be useful during application development to get useful error information while keeping the application running, but can generally be dangerous, because the application may be left in a bad state after an Error has been thrown.
VibePragmaLib Uses a pragma(lib) to link against OpenSSL. This is only useful for building without DUB.
VibeCustomMain Tells vibe.d to not use its own predefined main function. This is mutually exclusive to VibeDefaultMain. This is the default behavior since vibe.d 0.7.26.
VibeNoSSL Does not use OpenSSL to provide TLS/SSL functionality. The vibe.stream.tls module will be dysfunctional. Deprecated for 0.8.0 and up, see the HTTPS section instead
VibeUseOpenSSL11 Compiles the TLS module so that it is compatible with the 1.1.x branch of OpenSSL. Deprecated for 0.8.0 and up, see the HTTPS section instead
VibeUseOldOpenSSL Disables the use of features introduced in OpenSSL 1.0.1 or later, most notably ECDH curve selection. Use this to link against old versions of the OpenSSL library. Deprecated for 0.8.0 and up, see the HTTPS section instead

Handling segmentation-faults on Linux

While access violations on Windows usually trigger an exception with a convenient stack trace, on other operating systems D applications just terminate and possibly cause a core dump file to be written. However, there is a module hidden in the D runtime that enables such a stack trace also on Linux. Simply run the following code at program initialization:

import etc.linux.memoryerror;
static if (is(typeof(registerMemoryErrorHandler)))
	registerMemoryErrorHandler();
	

This currently works only on Linux x86 and x86-64.