tailscale-android: the Android client as a Go library plus a Kotlin app
Tailscale Android Client
At a glance
- What is it?
- Tailscale's Android repository is not a fork of the main client but a Kotlin UI bound to a Go library through gomobile, which is why building it needs a Go toolchain, an Android SDK and a Makefile full of recipes.
- Who is it for?
- This repository is the right starting point if you want to read how a mesh VPN client is wired into an Android app, or to track the Android client closely, and it is the wrong place to look for the networking itself, which lives in the main Tailscale repository. GitHub reports the last push on 2026-09-23, with the latest release 1.102.4 published 2026-09-11.
- Can I use it commercially?
- Yes. BSD-3-Clause 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?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Kotlin, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 10, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A Kotlin app wrapped around a Go library
The repository description is a single line, Tailscale Android Client, and the language GitHub reports is Kotlin. That is true of the user-facing layer and misleading about the whole. The root contains a `go.mod` declaring the module `github.com/tailscale/tailscale-android` and requiring `tailscale.com` at a prerelease version alongside `github.com/tailscale/wireguard-go` and `golang.org/x/mobile`.
So the architecture is a Go library, `libtailscale/`, compiled for Android through gomobile, with `android/` holding the Kotlin application on top. The `android/` directory, the `integration/` directory for emulator-backed Go integration tests, and `tool/` for tooling make that split visible in the tree. The Go dependency on `golang.org/x/mobile` is the gomobile bridge, and the WireGuard dependency is how the data path terminates on the device.
The Go requirement is strict. The README says only the latest Go release and any beta or release candidate builds are supported, currently Go 1.14 as a module-mode baseline, and that earlier versions or GOPATH mode might work but are not being kept working. `go.mod` in fact asks for go 1.27.1, which is the current toolchain line. The tension between the README's prose and the module file is a matter of the README predating a toolchain bump, and the module file is what the build will enforce.
Four build environments, all pointing at the same Makefile
The README offers Android Studio, a plain SDK, Docker, or Nix, and every route ends at the same Makefile recipes. Whatever you choose, you need a Go runtime and the Android SDK, and the components install themselves with one target:
make androidsdkFor the Android Studio route the steps are to install Go, install Android Studio, and from the Welcome screen open the SDK Manager and install the Android SDK Command-line Tools under the SDK Tools tab, then run `make androidsdk`. If you would rather not use Android Studio, the README says the makefile detects common paths, so `sudo apt install android-sdk` is sufficient on Debian and Ubuntu, and a non-standard location is handled by setting the `ANDROID_SDK_ROOT` environment variable. If the tools are not on your path because you installed them through the IDE, `make androidpath` prints the correct path to export.
make androidpath
make apk
make installThe last two are the actual build and install steps. `make apk` builds the package and `make install` puts it on a connected device, which is the shortest useful path once your environment is set up.
Nix and Docker remove the toolchain setup entirely
The Nix route is the tidiest and the README treats it as a first class option. It needs Nix 2.4 or later and the flakes feature enabled by an alias:
alias nix='nix --extra-experimental-features "nix-command flakes"'
nix developThe flake provides host tools such as Java, `make`, `curl` and `git`, and points the build at a repo-local Android SDK in `./android-sdk`, which the README says is ignored by Git and reused across builds. Inside that shell you still run `make androidsdk` once, then build normally with `make tailscale-debug`, and the debug APK lands at `./tailscale-debug.apk`.
For one-shot use without entering the shell, the same recipes run through `--command`:
nix develop --command make androidsdk
nix develop --command make tailscale-debugThere is also a Kotlin-only loop that skips the gomobile binding step, which is the expensive part when you are only changing UI code:
nix develop --command bash -lc 'cd android && ./gradlew ktfmtCheck compileDebugKotlin'The Docker route is the older one and shows its age in a small typo: the README notes the docker makefile recipes will preserve the image and remove the container on completion, with a stray letter in the word. Cached images need rebuilding when the build environment or toolchain changes, and the image name is parameterized in the makefile. `make docker-shell` is the entry point.
Version stamping from wall-clock time
Release versioning in this project is unusual enough to be worth reading closely, because it explains the release tag format. The README says `make tag_release` stamps the Play Store version code, updates the version name, and tags the current commit, and that the version code is derived from wall-clock time, minutes since the Unix epoch, at release time, then committed into `android/build.gradle`.
The stated benefit is monotonicity: the number increases across all builds and all branches while staying fixed for any given commit. The cost is that version codes are not small integers you can reason about, and that the number is a property of when you released rather than of the release itself.
That is why the release tags look like `1.102.4-t3caf7d9e7-g8fbef364a`. GitHub reports 1.102.4 published 2026-09-11, 1.102.3 on 2026-08-21 and 1.102.2 on 2026-08-07. Each tag carries a version, a truncated commit hash and another hash, which is consistent with the generated scheme rather than with a hand-typed release process.
The Makefile reinforces the pinning discipline elsewhere too: it reads `androidApiLevel` and `androidBuildToolsVersion` out of `android/gradle.properties` and fails with an error if `androidApiLevel` is missing, so a build cannot silently proceed against the wrong SDK level.
Where users actually get the app
This matters for anyone wondering whether building the repository is even necessary. The README lists four channels. The stable APKs come from the Tailscale Packages Stable Track and unstable builds from the Unstable Track, and those APKs include all supported platforms and architectures. The Google Play Store is the route for compact APKs, Android TV, or automatic updates, and there is a beta testing track there for testing new features before they ship to everyone. The Amazon Appstore covers Fire tablets and Fire TV devices.
The fourth channel carries a caveat worth reading in full. The F-Droid project builds the source code in this repository and maintains independently-built APKs, and the README states plainly that F-Droid builds are not released, updated, or verified by the Tailscale team. So an F-Droid install is a build from this source tree that the project itself does not stand behind for updates.
Building from source is therefore for development, auditing, or a device the Play Store does not serve, not for routine installation. If you only want the app, `make apk` is effort you do not need.
For hardware that has no Play Store at all, the README has a Fire Stick section: enable ADB debugging under Developer Options, then connect with `adb connect`, install the APK with `adb install -r`, and start the main activity with `adb shell am start`. Uninstalling is `adb shell pm uninstall com.tailscale.ipn`.
Contribution process still under construction, and a real one at that
The README's Contributing section is unusually candid. It places an animated `under_construction.gif` image, says pull requests are welcome, and then says the project is still working out its contribution process and tooling. A requirement is spelled out: commits need Developer Certificate of Origin Signed-off-by lines.
The signing requirement matters more than it first appears. DCO sign-off is the mechanism used by Linux kernel and many other projects to record that a contributor has the right to submit the code, and it is enforced by tooling rather than by good intentions. So even with the process unfinished, there is a floor.
Code style is also specified. The README says the ktmft plugin on the default setting should be used to autoformat all Java, Kotlin and XML files in Android Studio, with Format on Save enabled. The Nix loop above names the same tool as `ktfmtCheck`, so the formatter is consistent between the IDE and the command line.
Bugs are not filed here. The README directs issues about the code or the hosted service to the Tailscale issue tracker in the main repository, which is a reminder that this repository is one component of a larger product rather than a standalone project with its own community.
The Makefile also names two pinned images with dated tags, `tailscale-android-build-amd64-20260912-1` for the build environment and `tailscale-android-integration-amd64-20260912-1` for the integration test image that carries the emulator, system image, SDK, build tools, NDK and adb. Dated tags are deliberate: they force a rebuild when the toolchain moves, which is the right call for reproducibility but means you rebuild when the project moves rather than when you do.
Editorial conclusion
This repository is the right starting point if you want to read how a mesh VPN client is wired into an Android app, or to track the Android client closely, and it is the wrong place to look for the networking itself, which lives in the main Tailscale repository. GitHub reports the last push on 2026-09-23, with the latest release 1.102.4 published 2026-09-11. Start with `nix develop` followed by `make androidsdk` and `make tailscale-debug`, since that path needs the least manual setup.
Frequently asked questions
Can I build the Tailscale Android client myself?
Yes, but the build is not just an Android project. You need a Go runtime and the Android SDK, and `make androidsdk` installs the SDK components. The `nix develop` shell provides Java, `make`, `curl` and `git` and points at a repo-local SDK, after which `make tailscale-debug` produces `tailscale-debug.apk`. You do not need to build it unless you are developing, auditing or targeting a device without a store.
How does the Android client relate to the main Tailscale repository?
The networking lives in the main project. `go.mod` in this repository requires `tailscale.com` at a prerelease version, and the `libtailscale/` directory holds the Go side that is bound to Android through gomobile, with the Kotlin application in `android/`. Issues about the code or the hosted service go to the main Tailscale issue tracker, not here.
Why do the release tags contain hashes after the version number?
Because release versioning is generated rather than typed. `make tag_release` stamps a Play Store version code derived from minutes since the Unix epoch at release time, updates the version name and tags the commit, so tags look like `1.102.4-t3caf7d9e7-g8fbef364a`. The README says the code increases monotonically across builds and branches while staying fixed for any given commit.
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/tailscale-tailscale-android)