# Artalk: a self-hosted comment system with a Go server and a 40KB Vanilla JS client

> Artalk pairs a Golang backend with a framework-agnostic frontend widget, deployed through Docker or a binary. It is a reasonable fit for blogs that want comment ownership on their own server, and a poor fit for anyone who wants zero operations work.

**ArtalkJS/Artalk** — 🌌  Your Self-hosted Comment System. | 自托管评论系统

- Repository: https://github.com/ArtalkJS/Artalk
- Website: https://artalk.js.org
- Stars: 2,340 · Forks: 211
- Language: Go
- License: MIT
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/artalkjs-artalk

## The problem Artalk solves, and who it is for

A blog that wants comments has two options: hand the conversation to a third party, or run the comment stack itself. Artalk takes the second path. The README describes it as "an intuitive yet feature-rich comment system, ready for immediate deployment into any blog, website, or web application", and the repository is structured around that split: a Go server in the repository root and cmd/, and a TypeScript client under ui/ and server/.

The intended user is someone who already pays for a VPS or runs a Docker host and does not want comment text, email addresses and IP-derived region data sitting in another company's database. The feature list makes the scope clear: social login, email notification, captcha, moderation, image upload, Markdown, multi-site isolation, comment voting and sorting, page-view statistics, an admin sidebar, a command line, and an OpenAPI-format HTTP API. That is a full application, not a drop-in script tag.

It is not aimed at someone who wants comments working in five minutes with no server. Every capability above has to be configured, and the configuration lives in a file or in environment variables on a machine you own.

## How the Go server and the frontend widget fit together

The architecture is a conventional client-server split with an unusually small client. The README states the client is roughly 40KB, written in pure Vanilla JS and framework-agnostic. The server is written in Go, which is why the Dockerfile builds with golang:1.26.5-alpine3.24 and produces a single binary at /source/bin/artalk.

Data flows in one direction for reads. The browser loads the widget, the widget calls the server over HTTP, and the server answers from its database. The go.mod file shows the storage and caching dependencies: go-sql-driver/mysql for MySQL, libtnb/sqlite for SQLite, and gocache with bigcache, memcache and redis stores. So a deployment can run on an embedded SQLite file or point at MySQL, with an optional cache layer in front. The same file lists gofiber/fiber/v2 as the HTTP framework and golang-jwt/jwt/v5 for tokens, which is how the admin password verification and social login sessions are likely carried.

Rendering happens in the browser, not on the server. That matters for caching: your page HTML can stay static while comments load separately. It also means a visitor with JavaScript disabled sees nothing, and a slow or unreachable Artalk server leaves an empty region on the page rather than a server-side error.

The Dockerfile exposes port 23366 and runs the binary with a host and port argument, which is the port the client must reach. The docker-compose.yml maps host 8080 to container 23366. Confusing those two numbers is the most likely first-deployment mistake.

## Installing Artalk with Docker and embedding the first comment box

The README gives a one-step Docker command. It publishes host port 8080 to the container's 23366, mounts a local data directory at /data, and sets the timezone, locale, default site name and site URL through ATK_ environment variables. The site name you pass here must match the site name in the client configuration later, because Artalk separates comments by site.

```bash
docker run -d \
    --name artalk \
    -p 8080:23366 \
    -v $(pwd)/data:/data \
    -e "TZ=America/New_York" \
    -e "ATK_LOCALE=en" \
    -e "ATK_SITE_DEFAULT=Artalk Blog" \
    -e "ATK_SITE_URL=https://example.com" \
    artalk/artalk-go
```

After the container starts, the server is listening on port 23366 inside the container, reachable on the host at 8080 in this example. In production you would put a reverse proxy in front of it and terminate TLS there, then point the client's server field at that HTTPS address.

The repository also ships a docker-compose.yml with the same shape, using TZ=Asia/Shanghai and ATK_LOCALE=zh-CN. If you prefer Compose, edit those environment values and the port mapping, then bring the stack up.

```yaml
services:
  artalk:
    container_name: artalk
    image: artalk/artalk-go
    restart: unless-stopped
    ports:
      - 8080:23366
    volumes:
      - ./data:/data
    environment:
      - TZ=Asia/Shanghai
      - ATK_LOCALE=zh-CN
      - ATK_SITE_DEFAULT=Artalk 的博客
      - ATK_SITE_URL=https://example.com
```

On the page side, the README shows the client initialization. The el selector must match an element that exists in your HTML, site must equal the ATK_SITE_DEFAULT you set on the server, server is the public URL of your Artalk instance, and pageKey identifies the individual page so comments are grouped correctly.

```ts
Artalk.init({
  el:      '#Comments',
  site:    'Artalk Blog',
  server:  'https://artalk.example.com',
  pageKey: '/2018/10/02/hello-world.html'
})
```

If comments do not appear, check those four values in that order. The README does not document a diagnostic mode for a mismatch, so the failure looks like an empty widget rather than an error message.

The README also notes other installation methods: binary files, go install, and package managers for Linux distributions, with the deployment guide linked as the place to learn more.

## Where Artalk is the wrong tool

The first limitation is operational. Artalk is a server you run. The README's own selling points are Docker deployment and self-hosting, which means backups, upgrades, TLS, and database maintenance are yours. If nobody on the team wants that responsibility, a hosted comment service is the honest choice, and Artalk's feature list will not compensate for an unpatched server.

The second is the client-side rendering model. Because the widget is JavaScript, comment content is not in the initial HTML. Search engines that do not execute JavaScript, and any reader with scripting disabled, see an empty container. For documentation sites where comments carry useful answers, that is a real loss.

The third is the configuration surface. Multi-site isolation, social login, captcha, email notification and push notifications each have their own settings, and the README links a separate documentation page for each. A default Docker run gives you a working comment box, but the moderation, notification and login behaviour people expect from a mature comment system requires reading several of those pages.

Finally, the README is silent on rollback and on downgrade behaviour between releases. The repository has a CHANGELOG.md and the feature list mentions version check and one-click upgrade, but the README does not document what happens if an upgrade goes wrong. Back up the /data volume before upgrading, because the documentation does not promise a way back.

## Artalk compared with Remark42 and Cusdis

Remark42 is the closest comparison in intent: a self-hosted comment engine with its own server and an embeddable widget. The difference in approach is the implementation language and the resulting deployment story. Remark42 is a single Go binary with its own storage and authentication model, and it treats privacy-oriented self-hosting as the central design constraint. Artalk is also a Go server, but it splits the project into a Go backend and a separately versioned TypeScript client published to npm, with a plugin system and an admin sidebar as separate frontend packages. That split is why Artalk can be embedded in a page with a small script and why the frontend can be extended without touching the server. It is also why the frontend and backend versions can drift, which Remark42's single-artifact model avoids.

Cusdis takes the opposite trade-off on weight. It is deliberately minimal: a small embeddable comment box with a simple moderation interface, rather than a system with page-view statistics, comment voting, an admin sidebar and a plugin API. If your requirement is a lightweight comment thread and you do not need the surrounding features, Cusdis is the smaller thing to operate. If you need multi-site management, social login and notification routing in one place, Artalk's feature list is the reason to pick it.

Twikoo is the other name that comes up in the same searches. It is a comment system deployed as a cloud function rather than as a long-running server, so the operational model is different in kind: you do not manage a container or a database process, but you also depend on the function platform's runtime and limits. Artalk's Docker image and /data volume give you a conventional server deployment instead.

## Maintenance, licence and upgrade cost

The repository is not archived, and the last push was on 2026-09-01. The most recent tagged release listed is v2.10.0 from 2026-07-24, with a nightly build published the following day. The gap before that is worth noting: v2.9.1 is dated 2024-09-18, so roughly twenty-two months separate those two stable tags. A project that ships a stable release every two years has a different upgrade rhythm from one that ships monthly, and you should plan accordingly rather than assuming frequent small upgrades.

The codebase is a pnpm monorepo. package.json declares packageManager pnpm@10.33.2 and requires Node >=22.19.0 and pnpm >=10.33.2, and go.mod declares go 1.26.5. Building from source therefore requires both toolchains at those versions; the Dockerfile handles this for you by installing pnpm@10.33.2 inside the builder stage. If you build the UI yourself, expect to match those versions or the build scripts will not run.

Upgrade cost is mostly the server binary plus the client script. The feature list advertises version check and one-click upgrade, and the Dockerfile creates a runner script at /usr/bin/artalk with an artalk-go alias, so container-based upgrades are a matter of pulling a new image and restarting against the same /data volume. The frontend is distributed on npm, so a version bump on the client side is a separate decision from the server upgrade.

The licence is MIT. That permits commercial and private use, modification and redistribution provided the copyright notice and permission notice are included. It is a permissive licence with no copyleft obligation and no requirement to publish your changes. This is a description of the licence text, not legal advice; if you redistribute Artalk inside a product, read the LICENSE file in the repository and, where it matters, take your own counsel.

## Conclusion

Adopt Artalk if you already run a server or Docker host and want comment data, moderation and page-view statistics under your own control. Do not adopt it if you want a hosted service with no operations work, or if your site cannot load a third-party JavaScript file from your own domain. Before committing, verify three things: that the ATK_SITE_DEFAULT value you pass at container start matches the site name in Artalk.init exactly, that your database of choice is reachable from the container, and that your reverse proxy forwards to port 23366 rather than the 8080 you published.

## FAQ

### How do I install Artalk on my own server?

The README's quickest path is a single docker run command that publishes host port 8080 to the container's 23366, mounts a local directory at /data, and sets TZ, ATK_LOCALE, ATK_SITE_DEFAULT and ATK_SITE_URL as environment variables. The README also lists binary files, go install, and Linux distribution package managers as alternatives, with the deployment guide linked for details.

### How do I add the Artalk comment box to a page?

Load the client and call Artalk.init with four values: el pointing at the container element, site matching the server's site name, server holding the public URL of your Artalk instance, and pageKey identifying the page. The README's example uses el: '#Comments', site: 'Artalk Blog', server: 'https://artalk.example.com' and pageKey: '/2018/10/02/hello-world.html'.

### What database does the Artalk server use?

The go.mod file lists drivers for MySQL (go-sql-driver/mysql) and SQLite (libtnb/sqlite), plus a cache layer (eko/gocache) with bigcache, memcache and redis stores. The README does not spell out which storage is the default, so check the configuration documentation before choosing one for production.

## Sources

- [ArtalkJS/Artalk on GitHub](https://github.com/ArtalkJS/Artalk)
- [License: MIT](https://github.com/ArtalkJS/Artalk/blob/master/LICENSE)
- [Project website](https://artalk.js.org)
- [README](https://github.com/ArtalkJS/Artalk/blob/master/README.md)
- [Releases](https://github.com/ArtalkJS/Artalk/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/artalkjs-artalk
