Self-hosted service
wormi4ok/evernote2md avatar
wormi4ok/evernote2md

evernote2md: a Go CLI that turns .enex exports into a directory of Markdown notes

Convert Evernote .enex files to Markdown

1,112 stars95 forksGoMIT

At a glance

What is it?
evernote2md converts Evernote exports in the .enex format into one Markdown file per note, with optional front matter, attachment files split into image and file directories, and links that keep pointing at the right asset. The author calls it zero dependencies because the released binary needs nothing installed, and the Docker image is a two stage Alpine build.
Who is it for?
Adopt evernote2md if you are leaving Evernote behind and have an .enex export to hand, since it produces one Markdown file per note with attachments written out and links rewritten, which is exactly what a static site or note vault needs. Do not adopt it expecting to read from Evernote directly, because the tool only consumes exports you produce yourself, and the README warns that newer Evernote apps cap manual selection at 50 notes at a time.
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?
Yes. The repository last received commits 8 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the converter produces on disk

evernote2md is a CLI tool that converts Evernote notes exported in the .enex format into a directory of Markdown files. The output shape is the interesting part of the design.

You get one Markdown file per note, with optional front matter for Jekyll and other static site generators. Attachments are converted to files, and two directories are created for them: image for images and file for other attachments such as PDFs. The tool retains correct links to attachments, so the Markdown points at the extracted file rather than at an embedded Evernote resource identifier that means nothing outside Evernote.

Evernote tags are inserted into the notes as text entries with customizable formatting, and highlighted text in the original note is shown as such. File created and modified dates are set equal to the note attributes, which is a small touch that matters if you then sort by date in a file system or feed the notes into a git repository.

The tag formatting is configurable through a --tagTemplate option, and the README points to a wiki article on custom tag templates for the details. The flag --help lists all available options.

The README's recommendation for anything beyond a flat directory is to use a separate tool, mdmv, described as a Move Markdown files tool, for putting exported notes into folders or structuring them in a custom way. That split of responsibilities is sensible: the conversion is one concern and the file organisation is another.

Installing the binary, and what zero dependencies means here

Installation is a Homebrew command or a manual download.

bash
brew install evernote2md

The manual route is to download the latest release for your OS from the GitHub releases page. The README calls out macOS specifically, pointing to a wiki page with a macOS FAQ if you have problems running the tool, which is worth reading before assuming something is wrong with your export.

The zero dependencies claim in the feature list needs a small clarification, because the go.mod file is not empty. The module requires doublestar for glob matching, spinner for the progress display, durafmt for duration formatting, logutils for log filtering, flaggy for the flag parsing, godown for Markdown escaping, go-diff for diffing, and golang.org/x/net.

The distinction is between build-time and run-time dependencies. The README's promise is that you download and run the binary and nothing needs to be installed alongside it, which is true. The Go module dependencies are compiled into the executable. There is also a replace directive pointing godown at the author's own fork, so the tool controls that dependency's version.

The Docker image makes the same point in a different way, and it is a well-built two stage image.

dockerfile
FROM golang:1.27-alpine3.24 AS build
ENV CGO_ENABLED=0
RUN go test ./... && go install -trimpath -ldflags "-s -w -X main.version=$(git describe --tags --abbrev=0)"

FROM alpine:3.24
COPY --from=build /go/bin/evernote2md /
ENTRYPOINT ["/evernote2md"]
CMD [ "-h" ]

CGO is disabled so the binary is static, the tests run inside the image build, the version string is injected at build time from the git tag, and the runtime image contains nothing but the binary. The default command is -h, so a bare docker run prints the help rather than erroring.

Input handling, from a single file to a glob pattern

The usage line is short.

bash
evernote2md (flags) [input] [outputDir]

The input argument is flexible in three ways, and this is the part of the tool that saves the most time on a real export. It can be a single file, a directory containing exported files, or a glob pattern, with the README giving exports/My*.enex and exports/**/*.enex as examples. The double star form is what lets you pull an entire tree of notebooks in one pass, and the doublestar dependency in go.mod is what makes that pattern work.

If the output directory is not specified, ./notes is used. So the shortest useful invocation needs only an input path, and the default lands the result in a notes directory next to where you ran the command.

The Docker invocation mounts the current directory at /tmp and sets the working directory there, so a relative output path behaves the same as it does locally.

bash
docker run -t --rm -v "$PWD":/tmp -w /tmp wormi4ok/evernote2md:latest (flags) [input] [outputDir]

The flags are shown in parentheses in the README's Docker example, and the -t flag with --rm keeps the output attached to your terminal so the progress spinner is visible, while --rm discards the container afterwards.

Exporting from Evernote, and the 50 note limit

The converter only sees what Evernote gives it, so the export step is where the work actually is, and the README treats it as part of the tool's documentation.

There is a link to the Evernote Help Center article on backing up and exporting notes and notebooks, and then a warning. Newer versions of the Evernote App do not allow selecting more than 50 notes at a time, and the README suggests exporting an entire Notebook instead, with a wiki page on exporting a notebook.

That is a genuinely important operational detail, because the failure mode is silent. If you select 50 notes, export, convert, and assume you have your archive, you have a directory of 50 Markdown files and no error message. The tool is not at fault; the export boundary is.

The same applies to a whole library. If a notebook contains thousands of notes, you need the notebook-level export, and for a multi-notebook library that is a set of exports rather than one.

There is no check in the tool for completeness, and it would be reasonable to want one, an expected note count against the number of Markdown files written. The README does not mention such a feature, so treat the count of exported files as something you verify yourself.

Project structure, release cadence and licence

The repository is a small Go project with a conventional layout. The root holds main.go, notes.go and their test files, plus main_test.go and notes_test.go, and there are internal/, file/ and encoding/ packages for the pieces of the conversion. A Dockerfile, a Makefile, an e2e.sh script and a .release.yml sit alongside them, with renovate.json for dependency updates and a .github directory for the CI workflow.

The Makefile is a two line build with a version suffix, and the suffix defaults to rc1, which is a hint about how release candidates are cut in this project.

makefile
LATEST_TAG := $(shell git describe --abbrev=0 --tags)
SUFFIX ?= rc1

build:
	 go build -trimpath -o bin/evernote2md -ldflags "-s -w -X main.version=$(LATEST_TAG)-${SUFFIX}"

The same version stamping pattern appears in the Dockerfile, so the binary reports the tag it was built from.

The recent releases are v0.23.0 on 2026-08-23, v0.22.2 on 2026-01-09 and v0.22.1 on 2025-08-18, and the last push was on 2026-10-10. So the project is alive and shipping, and it is pre-1.0, which for a converter means the output format could still change between versions. If you plan to re-run the conversion on a future export and diff the results, pin the version.

The licence is MIT, with the file named LICENCE rather than LICENSE at the root. The Go version required is 1.27.0 in go.mod, and the Docker build uses golang:1.27-alpine3.24 with a runtime on alpine:3.24.

Editorial conclusion

Adopt evernote2md if you are leaving Evernote behind and have an .enex export to hand, since it produces one Markdown file per note with attachments written out and links rewritten, which is exactly what a static site or note vault needs. Do not adopt it expecting to read from Evernote directly, because the tool only consumes exports you produce yourself, and the README warns that newer Evernote apps cap manual selection at 50 notes at a time. Verify first which notes actually made it into your export, since the Evernote app is the component that decides what to include, and check the macOS FAQ linked from the README if the binary will not run on your machine.

Frequently asked questions

How do I convert Evernote notes to Markdown with evernote2md?

Run evernote2md with an input and an output directory, where the input can be a file, a directory of exported files or a glob pattern such as exports/**/*.enex. If the output directory is omitted, ./notes is used, and one Markdown file is written per note with attachments extracted into image and file folders.

How do I install evernote2md?

Run brew install evernote2md, or download the latest release for your OS from the GitHub releases page. There is also a Docker image, run as docker run -t --rm -v "$PWD":/tmp -w /tmp wormi4ok/evernote2md:latest, and macOS users are pointed to a wiki FAQ if the binary will not run.

Does evernote2md read from Evernote directly?

No. It converts .enex exports that you produce yourself from the Evernote app. The README warns that newer Evernote versions do not allow selecting more than 50 notes at a time, and recommends exporting entire notebooks instead.

How can I change how evernote2md formats Evernote tags?

Use the --tagTemplate option, which changes the way tags are formatted, with the details in the wiki article on custom tag templates. Running the tool with --help shows all available options.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. wormi4ok/evernote2md on GitHub
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/wormi4ok-evernote2md.svg)](https://hysenlabs.com/projects/wormi4ok-evernote2md)

Was this useful?