Automatically upload images in the Typora editor

Typora is my favorite markdown editor, and to this day, I find it unmatched in terms of ease of use. For more complex blog posts, I write them in Typora before uploading. Typora boasts a wealth of features, including:
- Support for tables
- LaTeX syntax support for writing equations
- Drag-and-drop functionality for images to generate corresponding markdown syntax
- Support for various HTML tags, such as iframe, video, ruby, and more
- Customizable themes (written in CSS)
- Built-in file and folder browsing and switching capabilities
- Numerous other handy features
These well-crafted functionalities make Typora an indispensable tool for me.
However, I do have one frustration while using it: image uploads. Typora only inserts the image path into the markdown, like this syntax:

If you copy it as is, it will result in broken images on the web, because users cannot access your local computer paths; you need to upload the images to cloud storage or a server. Handling this manually can be cumbersome, especially when images are large, as I often want to compress them before uploading. The thought of adding another step can disrupt the flow of my writing.
I couldn’t help but wonder if there was a way to upload images directly without leaving the editor. Typora supports powerful drag-and-drop functionality for images, and copying and pasting from the web works perfectly—it’s a fantastic UI.
Finally, I discovered this:
I was amazed! This feature allows you to define actions when you drop an image into the editor, such as automatically moving it to a specific folder or uploading the image. Even better, you can define your own command to upload images!

In this upload command, I compressed the image, uploaded it to S3, and returned the image URL. The remaining UI and status interactions are handled by Typora, allowing for a completely seamless image upload experience!
The final result looks like this:
Implementation
You can check out my code on GitHub (written in Node.js). The implementation is quite straightforward, but I just wanted to get it done quickly, so I installed the necessary packages and dove right in. If you prefer a DIY approach, feel free to try writing it from scratch. Currently, it only supports uploads to S3.
Conclusion
Since then, a new door has opened in my life; I no longer hesitate to post simply because I don’t want to deal with photo uploads. I’m sharing this with everyone who loves creating content with markdown.
Related Posts
- When Measurement Becomes the Goal: From Window Tax to PR Counts I once wrote a small tool to count how many PRs I had contributed in a quarter, how many reviews I had left, and how many tickets I had closed, hoping to use the numbers to prove my output to my manager. My manager simply said performance is not judged by output alone. Only years later did I understand—when measurement becomes the goal, it is no longer a good measure. From Britain’s window tax and the Hanoi rat bounty to evaluating developers by PR count today, the mechanism is exactly the same.
- Using Cloudflare Images for Image Storage and Transformation Putting an image on a web page is the easiest thing in frontend. But doing it properly — resizing, generating every format, holding up under traffic — turns into a whole solution of its own. I ended up handing all of it to Cloudflare Images and keeping just one original.
- Stop Using Access Keys Already Access Keys are an easily overlooked security risk on AWS. Use OIDC with IAM Roles so GitHub Actions can securely access AWS resources without any secrets.
- Database Primary Keys: AUTO_INCREMENT, UUID, and UUIDv7 Backend developers often have to decide on a primary key: auto increment or UUID? What about collisions? How much faster is UUIDv7 compared with created_at + index? After benchmarking 20 million rows and looking at the design trade-offs, this post gives you the answer.