41554 blogs · [ { "id": "01a08791-0eba-72b9-85e6-5805fe223bbb", "title": "Manual Code Review is Dead", "url": "https://joshkaramuth.com/blog/manual-code-review-dead/", "published_at": "2026-08-10T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-5805fe3e33a9", "title": "How to Fix Permission Issues with Docker Volumes", "url": "https://joshkaramuth.com/blog/docker-volumes-permission/", "published_at": "2026-07-20T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-5805feb0c271", "title": "Simplicity Doesn't Sell (And I'm Tired of Being Called Lazy For It)", "url": "https://joshkaramuth.com/blog/simplicity-doesnt-sell/", "published_at": "2026-07-17T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-5805ff359719", "title": "I Used AWS Cognito for a Startup. I Wouldn't Do It Again.", "url": "https://joshkaramuth.com/blog/aws-cognito-authentication-startup-nightmare/", "published_at": "2026-07-10T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-5805ffa96d5a", "title": "How I Deploy Web Apps With a Single Command", "url": "https://joshkaramuth.com/blog/web-app-deployment/", "published_at": "2026-06-13T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-5805ffd937e6", "title": "How I Fixed Frontend-Backend Desync with Hey API and FastAPI", "url": "https://joshkaramuth.com/blog/hey-fast-api-react/", "published_at": "2026-03-26T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-5805ffecbfde", "title": "Boto3 Is Gaslighting Me About My Athena Query Parameters", "url": "https://joshkaramuth.com/blog/boto3-athena/", "published_at": "2025-11-13T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-58060039a433", "title": "Wireguard Locked Me Out of My Own Server, and I'm Not Even Mad", "url": "https://joshkaramuth.com/blog/wireguard-scripts/", "published_at": "2025-11-11T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-5806003c153e", "title": "Python and Typescript for Life", "url": "https://joshkaramuth.com/blog/fullstack-python-typescript/", "published_at": "2025-10-20T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-58060067b50e", "title": "Stop Putting JWTs in LocalStorage. Seriously. Here's How to Do It Right.", "url": "https://joshkaramuth.com/blog/secure-jwt/", "published_at": "2025-10-15T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-580600d4a8c5", "title": "Why I Stick With HTMX Even If It Sucks", "url": "https://joshkaramuth.com/blog/htmx-sucks/", "published_at": "2025-09-12T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-580600fa9596", "title": "Level Up Your Django Views with the ViewModel Pattern", "url": "https://joshkaramuth.com/blog/django-view-model/", "published_at": "2025-09-04T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-5806017bf71d", "title": "The Ghost in the Migration: Why Your Model's Methods Disappear", "url": "https://joshkaramuth.com/blog/django-historical-models/", "published_at": "2025-09-01T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-580601915023", "title": "How I deploy Python/Django Apps as a Solo Dev", "url": "https://joshkaramuth.com/blog/django-deployment/", "published_at": "2025-08-24T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-580601c9648d", "title": "Stop Trusting Your API: How to Build a Bulletproof Frontend with Zod and React Query", "url": "https://joshkaramuth.com/blog/tanstack-zod-dto/", "published_at": "2025-08-21T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-580601edad61", "title": "On the Fence: My Affair with HTMX and the Enduring Allure of React", "url": "https://joshkaramuth.com/blog/react-vs-htmx/", "published_at": "2025-08-19T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-5806026fc76f", "title": "I Used DynamoDB for 2 Years. Here’s Why I recommend SQL.", "url": "https://joshkaramuth.com/blog/dynamodb-vs-sql/", "published_at": "2025-08-15T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-580602c5e563", "title": "Nvidia, Kubuntu, and My Reluctant Return to Windows 11", "url": "https://joshkaramuth.com/blog/linux-nvidia-still-sucks/", "published_at": "2025-05-14T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-5806035abd8a", "title": "Web Components: Powerful, Yes. A Joy to Write? Not Quite (Coming from React)", "url": "https://joshkaramuth.com/blog/web-components-vs-react/", "published_at": "2025-05-12T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-5806042d25d3", "title": "Break django-admin commands into subcommands", "url": "https://joshkaramuth.com/blog/django-admin-atomic-commands/", "published_at": "2025-03-08T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-580604a18d71", "title": "Redundant Linux backups with a single command", "url": "https://joshkaramuth.com/blog/linux-backup/", "published_at": "2025-03-08T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-580604b2500c", "title": "A Battle-Tested Way to Structure React Projects", "url": "https://joshkaramuth.com/blog/reactjs-project-structure/", "published_at": "2025-03-03T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-58060561bc5c", "title": "How to handle 404 errors with htmx in Django", "url": "https://joshkaramuth.com/blog/django-htmx-not-found/", "published_at": "2025-02-12T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-580606226752", "title": "Why the HTML dialog element sucks", "url": "https://joshkaramuth.com/blog/html-dialog-sucks/", "published_at": "2025-02-04T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-58060667a9ca", "title": "Build a Reusable Component with Django Cotton and AlpineJS", "url": "https://joshkaramuth.com/blog/django-cotton-alpine-component/", "published_at": "2025-01-14T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-580607031525", "title": "Show Django forms inside a modal using HTMX", "url": "https://joshkaramuth.com/blog/django-htmx-modal-forms/", "published_at": "2024-12-25T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-580607e21a97", "title": "How to show a modal in Django + HTMX", "url": "https://joshkaramuth.com/blog/django-htmx-modal/", "published_at": "2024-12-16T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-5806080f2497", "title": "How and why to run your Docker apps without root", "url": "https://joshkaramuth.com/blog/docker-non-root/", "published_at": "2024-10-25T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-5806086c9cc7", "title": "Automated container deployment without a registry", "url": "https://joshkaramuth.com/blog/deploy-container-no-registry/", "published_at": "2024-10-23T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-5806087dc005", "title": "Docker is better than Podman", "url": "https://joshkaramuth.com/blog/docker-vs-podman/", "published_at": "2024-10-22T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-580608e8606f", "title": "Understanding Python Decorators thanks to Django", "url": "https://joshkaramuth.com/blog/python-decorators/", "published_at": "2024-10-14T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-5806091df70d", "title": "A script to \"Modernize\" your Linux CLI", "url": "https://joshkaramuth.com/blog/modernize-linux-script/", "published_at": "2024-10-13T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-58060a17fff9", "title": "I moved my blog from Ghost to Astro", "url": "https://joshkaramuth.com/blog/ghost-to-astro/", "published_at": "2024-10-12T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-58060ac9d83f", "title": "Show Django flash messages as toasts with Htmx", "url": "https://joshkaramuth.com/blog/django-messages-toast-htmx/", "published_at": "2024-10-11T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-58060b84ea75", "title": "Build an intuitive CLI app with Python argparse", "url": "https://joshkaramuth.com/blog/python-argparse-intuitive-cli/", "published_at": "2024-10-10T00:00:00+00:00" }, { "id": "01a08791-0eba-72b9-85e6-58060c104117", "title": "Forward SSH Agent Requests From WSL to Windows", "url": "https://joshkaramuth.com/blog/forward-wsl-ssh-agent-windows/", "published_at": "2024-10-03T00:00:00+00:00" }, { "id": "01a08791-0ebb-73c2-b254-710b3fa13921", "title": "How to implement RESTful routing in Django", "url": "https://joshkaramuth.com/blog/restful-routing-django/", "published_at": "2024-09-19T00:00:00+00:00" }, { "id": "01a08791-0ebb-73c2-b254-710b4029e7f8", "title": "Generate DKIM key pairs in Python", "url": "https://joshkaramuth.com/blog/generate-dkim-key-pairs-python/", "published_at": "2024-09-15T00:00:00+00:00" }, { "id": "01a08791-0ebb-73c2-b254-710b403afe7b", "title": "Robust Full-Stack Authentication with Django Allauth, React, and React Router", "url": "https://joshkaramuth.com/blog/django-allauth-react/", "published_at": "2024-09-04T00:00:00+00:00" }, { "id": "01a08791-0ebb-73c2-b254-710b40778d8b", "title": "Using Django Allauth without Username Field", "url": "https://joshkaramuth.com/blog/django-allauth-without-username-field/", "published_at": "2024-09-01T00:00:00+00:00" }, { "id": "01a08791-0ebb-73c2-b254-710b411c2c98", "title": "How to Remove Username from Django's Default User model", "url": "https://joshkaramuth.com/blog/remove-username-django-user-model/", "published_at": "2024-08-23T00:00:00+00:00" }, { "id": "01a08791-0ebb-73c2-b254-710b41818caf", "title": "Why CSRF token cookies don't need to be httpOnly", "url": "https://joshkaramuth.com/blog/csrf-token-cookies-dont-need-httponly/", "published_at": "2024-07-20T00:00:00+00:00" }, { "id": "01a08791-0ebb-73c2-b254-710b42489963", "title": "Send Templated Emails in NodeJS", "url": "https://joshkaramuth.com/blog/send-templated-emails-nodejs/", "published_at": "2024-03-22T00:00:00+00:00" }, { "id": "01a08791-0ebb-73c2-b254-710b4316b734", "title": "Populate Custom User Attributes When Signing Up Using Django Allauth", "url": "https://joshkaramuth.com/blog/custom-user-attributes-django-allauth/", "published_at": "2024-03-21T00:00:00+00:00" }, { "id": "01a08791-0ebb-73c2-b254-710b433913a8", "title": "Track Hubspot Events in a React SPA", "url": "https://joshkaramuth.com/blog/track-hubspot-events-react/", "published_at": "2024-03-20T00:00:00+00:00" }, { "id": "01a08791-0ebb-73c2-b254-710b43da9a6e", "title": "How to upload files to S3 using a Presigned Upload URL", "url": "https://joshkaramuth.com/blog/upload-files-s3-presigned-upload-url/", "published_at": "2024-03-03T00:00:00+00:00" }, { "id": "01a08791-0ebb-73c2-b254-710b44c42a8a", "title": "Identify Individual Requests in ExpressJS", "url": "https://joshkaramuth.com/blog/identify-requests-expressjs/", "published_at": "2024-01-24T00:00:00+00:00" }, { "id": "01a08791-0ebb-73c2-b254-710b44f52dd7", "title": "How to Store Passwords Securely in NodeJS", "url": "https://joshkaramuth.com/blog/store-passwords-securely-nodejs/", "published_at": "2024-01-23T00:00:00+00:00" }, { "id": "01a08791-0ebb-73c2-b254-710b452e1731", "title": "Verify Paddle Billing Webhook Signatures in Python", "url": "https://joshkaramuth.com/blog/verify-paddle-billing-webhooks-python/", "published_at": "2024-01-11T00:00:00+00:00" }, { "id": "01a08791-0ebb-73c2-b254-710b45345e7b", "title": "Generate good looking PDFs with WeasyPrint and Jinja2", "url": "https://joshkaramuth.com/blog/generate-good-looking-pdfs-weasyprint-jinja2/", "published_at": "2024-01-10T00:00:00+00:00" }, { "id": "01a08791-0ebb-73c2-b254-710b45efbac8", "title": "Encode base64 in JavaScript and Decode in Python: Part 2", "url": "https://joshkaramuth.com/blog/encode-base64-javascript-decode-python-part-2/", "published_at": "2023-10-15T00:00:00+00:00" }, { "id": "01a08791-0ebb-73c2-b254-710b46a1546d", "title": "Encode base64 in JavaScript and Decode in Python: Part 1", "url": "https://joshkaramuth.com/blog/encode-base64-javascript-decode-python-part-1/", "published_at": "2023-10-14T00:00:00+00:00" }, { "id": "01a08791-0ebb-73c2-b254-710b46c67a7f", "title": "Log to console with Sentry", "url": "https://joshkaramuth.com/blog/log-console-sentry/", "published_at": "2023-10-14T00:00:00+00:00" }, { "id": "01a08791-0ebb-73c2-b254-710b47972f7d", "title": "Use Python partial objects to write cleaner higher order functions", "url": "https://joshkaramuth.com/blog/python-partial-objects/", "published_at": "2023-10-14T00:00:00+00:00" } ] posts Claim your blog
Back to joshkaramuth.com
Blog · corpus.blog/blogs/joshkaramuth.com/posts

joshkaramuth.com

joshkaramuth.com

2026

2025

2024

2023