grunt-contrib-connect: a static server that is a Grunt task
Start a static web server.
At a glance
- What is it?
- grunt-contrib-connect starts a connect web server from inside a Grunt run, with options for ports, protocols, hostnames, live reload injection, custom middleware and a keepalive target. It is a small, stable plugin whose main constraint is that it lives and dies with the Grunt process.
- Who is it for?
- Adopt grunt-contrib-connect when your build already runs through Grunt and you need a static server for a test runner or a manual check in the same command, because a named target such as grunt connect:keepalive is a good fit for that and for scripts that expect a fixed port.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A server that exists only while Grunt is running
The plugin does one thing, and the README is blunt about it: start a connect web server. The useful detail is the lifetime. The server only runs as long as Grunt is running, and once Grunt's tasks have completed, the web server stops. That behaviour is not an accident of implementation but the design point, because the task was designed to be used in conjunction with another task that runs immediately afterwards, and the README names grunt-contrib-qunit as the example. The shape of a typical use is a build step, then a task that starts the server, then a test task that needs that server, then the end of the Grunt run. In that arrangement the server is a fixture rather than a service, which is exactly what a test runner wants. It also means the plugin is not a dev server you leave running in a terminal tab, and a project that wants one of those has to reach for the keepalive option, with the consequences that come with it.
keepalive and the trap of a task that never yields
The keepalive option is the one that changes the lifecycle, and the README flags its cost in a single sentence: if this option is enabled, any tasks specified after this task will never run. By default the server stops when the Grunt tasks complete, and keepalive changes that by keeping the server alive indefinitely. The option can also be enabled ad-hoc without editing the configuration, by running the task with a target and the keepalive flag appended, in the form grunt connect:targetname:keepalive, and the same syntax appears in the earlier example as grunt connect:keepalive. The practical reading is that keepalive turns a Grunt task into a long running process, so anything you wanted to run after it, a test suite, a second task, a cleanup step, is unreachable. Grunt users tend to reach for it when a task needs a manual look at a page, and it works, but it converts an automated command into something you have to stop by hand. The README does not describe any shutdown behaviour beyond that, so the exit path is the usual one, ending the Grunt process.
Ports, protocols and the wildcard hostname
The network options are where most of the friction sits. The port option is an integer with a default of 8000, and the task fails if the specified port is already in use unless useAvailablePort is set, which makes it look for the next available port after the configured one. The special values 0 and the question mark string are accepted to ask the system for an assigned port, which is the sane choice for test runs where several jobs may start at once. The protocol option is a string defaulting to http and may also be http2 or https, and the http2 support in the dependency list comes from the http2-wrapper package, which is how a plain connect server is taught to speak the newer protocol. The hostname option defaults to 0.0.0.0 and, as the README explains, a wildcard value makes the server reachable on any local IPv4 address, including a loopback address and the address assigned to an ethernet or wireless interface. The default is therefore wider than a loopback bind, and if your machine is on a shared network that is worth thinking about before you start a server on it.
Serving more than one root, and browse-able directories
The base option decides what is served and it accepts three shapes, which is where the flexibility comes from. As a string it is the base or root directory from which files are served, and the default is the project Gruntfile's directory, so a value of public serves that folder. As an array it is a list of strings or objects, serving several directories at once, and the README states that the last base given becomes the browse-able directory. As an object it carries path and options keys, where the options are handed straight to the serve-static module, which is how you configure caching behaviour such as a maxAge value. The separate directory option then overrides which directory is browse-able, and the README points at serve-index for the details of what that listing looks like. Two details are worth remembering. The default middleware set already includes the connect middlewares for static files and directory browsing, so you do not have to add them yourself, and when you do supply a middleware array you are replacing that default rather than extending it.
onCreateServer and middleware for the cases a static server cannot cover
Two options exist for behaviour that a plain file server cannot provide. The onCreateServer option takes a function, or an array of them, that is called after the server object is created, which is the hook for libraries that need the underlying server. The README gives a Socket.IO example, where the server is handed to the socket.io listener and the connection handler is registered on it.
grunt.initConfig({
connect: {
server: {
options: {
port: 8000,
hostname: '*',
onCreateServer: function(server, connect, options) {
var io = require('socket.io').listen(server);The middleware option is the other half, taking a function or an array of functions with the familiar request, response and next signature, so a middleware can end the response itself, as in the README example that answers with a plain greeting. The distinction between the two options is worth keeping straight. Middleware runs per request inside the connect stack and is the right place for request level behaviour, while onCreateServer runs once at startup and is the right place for anything that needs the server object, such as attaching a websocket layer or another protocol handler. A project that has outgrown static serving usually needs both, and the order of the middleware array is the order of execution.
livereload needs a companion, and open is a small wrapper
The livereload option is the one most likely to be misunderstood, and the README corrects the common assumption in a single italic line: this does not by itself perform live reloading. Setting it to anything but false injects a live reload script tag into the served page using the connect-livereload package, and it is intended to be used in tandem with grunt-contrib-watch or another task that triggers a live reload server when files change. A boolean uses the defaults, a number is treated as a port number used together with the configured hostname, and an object is passed to connect-livereload unchanged. The open option opens the served page in your default browser, and it accepts true, a URL to open, or an object with the target, appName and callback keys, which the README says are the only supported keys, configured through the opn package. The README also records a historical detail worth knowing if you read old answers: in v0.9.0 the open package was replaced with opn, with the configuration kept the same for backwards compatibility. The debug option sits alongside these, and it is about Grunt's own logging rather than the server, since it enables logging instead of requiring the command line debug flag.
A narrow dependency set and a slow release cadence
The package is small and the dependency list explains what it does. The static serving comes from connect, with serve-static for files and serve-index for directory listings, connect-livereload for the injected reload script, http2-wrapper for the http2 protocol option, morgan for request logging, open for opening a browser, portscanner for the port availability check, and async for the asynchronous control flow. The development dependencies are the usual Grunt family, with the internal task helper, jshint for linting and nodeunit for the tests, and the test script is simply grunt test. The plugin is MIT licensed, the entry point is tasks/connect.js, and the published files are the tasks directory. The release history is slow by design of the maintainers rather than by neglect, with the only listed release being v5.0.0 from 2024-07-06 and the README heading showing v5.0.1, while the last push to the repository was on 2026-04-07. The package declares support for Node 16 and later, which is the practical floor to check before you add it to a project on a newer runtime.
Editorial conclusion
Adopt grunt-contrib-connect when your build already runs through Grunt and you need a static server for a test runner or a manual check in the same command, because a named target such as grunt connect:keepalive is a good fit for that and for scripts that expect a fixed port. Do not adopt it as a production server or as a general dev server outside a Grunt workflow, because the server stops as soon as the Grunt tasks finish unless keepalive is set, and keepalive in turn blocks every task that would follow it. Before you rely on it, check that the port you choose is free or set useAvailablePort, since the task fails when the port is already taken, and confirm your Node version is 16 or later, which is what the package declares.
Frequently asked questions
How do I install and enable grunt-contrib-connect?
Install it as a development dependency with npm install grunt-contrib-connect --save-dev, then enable it in the Gruntfile with grunt.loadNpmTasks('grunt-contrib-connect'). The task is then run with the grunt connect command.
Why does the web server stop when my Grunt task finishes?
The server only runs as long as Grunt is running, by design, so it can be used together with a task that runs immediately afterwards such as the qunit task. Setting the keepalive option keeps it running indefinitely, but the README notes that any tasks specified after that task will never run.
What happens if the port is already in use?
The task fails if the specified port is already in use, unless useAvailablePort is set, in which case it looks for the next available port after the configured one. You can also use the special values 0 or the question mark string to have a system assigned port.
Does the livereload option reload the page on its own?
No. The README states that it does not by itself perform live reloading, only injecting a live reload script tag into the page using connect-livereload. It is intended to be used in tandem with grunt-contrib-watch or another task that triggers a reload when files change.
How do I serve several directories or add my own request handling?
The base option accepts a string, an array of bases, or an object with path and options that are passed to serve-static, and the directory option sets which directory is browse-able. For custom behaviour, middleware takes functions with the request, response and next signature, and onCreateServer runs a function once the server object exists, for example to attach a Socket.IO listener.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/gruntjs-grunt-contrib-connect)Was this useful?