<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: buildbasekit</title>
    <description>The latest articles on DEV Community by buildbasekit (@buildbasekit).</description>
    <link>https://dev.to/buildbasekit</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3822341%2Fd883b38f-434e-4524-aa08-2a8372503386.webp</url>
      <title>DEV Community: buildbasekit</title>
      <link>https://dev.to/buildbasekit</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/buildbasekit"/>
    <language>en</language>
    <item>
      <title>I’m crash testing FiloraFS-Lite under load (p95, pressure, failures)</title>
      <dc:creator>buildbasekit</dc:creator>
      <pubDate>Mon, 27 Apr 2026 08:59:11 +0000</pubDate>
      <link>https://dev.to/buildbasekit/im-crash-testing-filorafs-lite-under-load-p95-pressure-failures-24lj</link>
      <guid>https://dev.to/buildbasekit/im-crash-testing-filorafs-lite-under-load-p95-pressure-failures-24lj</guid>
      <description>&lt;p&gt;I started running crash tests on &lt;a href="https://buildbasekit.com/boilerplates/filora-fs-lite/" rel="noopener noreferrer"&gt;FiloraFS-Lite&lt;/a&gt; to see how it actually behaves under pressure.&lt;/p&gt;

&lt;p&gt;Not benchmarks. Not ideal conditions.&lt;br&gt;
Real stress.&lt;/p&gt;

&lt;p&gt;The focus is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;where it starts breaking&lt;/li&gt;
&lt;li&gt;how early signals show up (p95, pressure)&lt;/li&gt;
&lt;li&gt;what fails first under sustained load&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What I’m testing right now
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;increasing RPM until the system shows pressure&lt;/li&gt;
&lt;li&gt;tracking how latency (p95) degrades&lt;/li&gt;
&lt;li&gt;observing write pressure under continuous load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I already have logs from initial runs.&lt;/p&gt;

&lt;p&gt;But instead of rushing conclusions, I’m validating signals properly before sharing anything.&lt;/p&gt;

&lt;p&gt;No assumptions. Just observed behavior.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;Small-scale tests looked fine.&lt;/p&gt;

&lt;p&gt;But real systems don’t fail in clean scenarios.&lt;/p&gt;

&lt;p&gt;They fail when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;load spikes&lt;/li&gt;
&lt;li&gt;resources get constrained&lt;/li&gt;
&lt;li&gt;edge cases stack together&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s the environment I’m trying to simulate.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I’ll share next
&lt;/h2&gt;

&lt;p&gt;Once analysis is done, I’ll publish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what broke first&lt;/li&gt;
&lt;li&gt;early warning signals&lt;/li&gt;
&lt;li&gt;what actually mattered vs noise&lt;/li&gt;
&lt;li&gt;what needs to change&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you’ve done similar crash or stress testing:&lt;/p&gt;

&lt;p&gt;What signal usually shows up first for you under load?&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>performance</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Setting Up Auth in 2026: AI Is Fast, But Boilerplates Still Win</title>
      <dc:creator>buildbasekit</dc:creator>
      <pubDate>Sat, 18 Apr 2026 16:47:50 +0000</pubDate>
      <link>https://dev.to/buildbasekit/setting-up-auth-in-2026-ai-is-fast-but-boilerplates-still-win-8of</link>
      <guid>https://dev.to/buildbasekit/setting-up-auth-in-2026-ai-is-fast-but-boilerplates-still-win-8of</guid>
      <description>&lt;p&gt;Let’s be honest.&lt;/p&gt;

&lt;p&gt;Auth is still one of the most frustrating parts of building a backend.&lt;/p&gt;

&lt;p&gt;Even in 2026.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Reality
&lt;/h2&gt;

&lt;p&gt;Setting up authentication today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;By yourself&lt;/strong&gt; → 8–15 hours
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;With AI&lt;/strong&gt; → 2–3 hours
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;With a good boilerplate&lt;/strong&gt; → 2–3 minutes
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI helped a lot.&lt;/p&gt;

&lt;p&gt;But it didn’t remove the hardest part.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Problem Isn’t Code
&lt;/h2&gt;

&lt;p&gt;Most devs think auth is about writing code.&lt;/p&gt;

&lt;p&gt;It’s not.&lt;/p&gt;

&lt;p&gt;It’s about decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JWT or session?&lt;/li&gt;
&lt;li&gt;Refresh tokens?&lt;/li&gt;
&lt;li&gt;Role system?&lt;/li&gt;
&lt;li&gt;Multi-tenant or not?&lt;/li&gt;
&lt;li&gt;Middleware structure?&lt;/li&gt;
&lt;li&gt;Edge cases?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI can generate code fast.&lt;/p&gt;

&lt;p&gt;But it &lt;strong&gt;doesn’t give you a clean, reliable system&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So you still spend hours:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;prompting
&lt;/li&gt;
&lt;li&gt;fixing inconsistencies
&lt;/li&gt;
&lt;li&gt;restructuring code
&lt;/li&gt;
&lt;li&gt;debugging flows you didn’t design
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s where the time goes.&lt;/p&gt;




&lt;h2&gt;
  
  
  What AI Actually Solves
&lt;/h2&gt;

&lt;p&gt;AI is great at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generating endpoints
&lt;/li&gt;
&lt;li&gt;writing controllers
&lt;/li&gt;
&lt;li&gt;suggesting schemas
&lt;/li&gt;
&lt;li&gt;speeding up repetitive work
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It reduces typing.&lt;/p&gt;

&lt;p&gt;But typing was never the bottleneck.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Boilerplates Win
&lt;/h2&gt;

&lt;p&gt;A good boilerplate removes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;decision fatigue
&lt;/li&gt;
&lt;li&gt;architecture mistakes
&lt;/li&gt;
&lt;li&gt;incomplete flows
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;working auth system
&lt;/li&gt;
&lt;li&gt;clean structure
&lt;/li&gt;
&lt;li&gt;tested flows
&lt;/li&gt;
&lt;li&gt;production-ready defaults
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And most importantly:&lt;/p&gt;

&lt;p&gt;👉 everything already fits together&lt;/p&gt;

&lt;p&gt;No guessing. No patching.&lt;/p&gt;




&lt;h2&gt;
  
  
  AI + Boilerplate &amp;gt; AI Alone
&lt;/h2&gt;

&lt;p&gt;This is the key shift.&lt;/p&gt;

&lt;p&gt;Boilerplates don’t compete with AI.&lt;/p&gt;

&lt;p&gt;They &lt;strong&gt;make AI usable&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;With a boilerplate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI works inside a solid structure
&lt;/li&gt;
&lt;li&gt;You extend instead of rebuild
&lt;/li&gt;
&lt;li&gt;Less debugging, fewer surprises
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI gives fragments
&lt;/li&gt;
&lt;li&gt;You connect everything
&lt;/li&gt;
&lt;li&gt;Things break in subtle ways
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Quick Comparison
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Without Boilerplate
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Generate auth with AI
&lt;/li&gt;
&lt;li&gt;Fix token logic
&lt;/li&gt;
&lt;li&gt;Add middleware
&lt;/li&gt;
&lt;li&gt;Handle refresh flow
&lt;/li&gt;
&lt;li&gt;Patch security gaps
&lt;/li&gt;
&lt;li&gt;Refactor structure
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Time:&lt;/strong&gt; 2–3 hours (best case)&lt;/p&gt;




&lt;h3&gt;
  
  
  With Boilerplate
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Clone repo
&lt;/li&gt;
&lt;li&gt;Add env values
&lt;/li&gt;
&lt;li&gt;Start server
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Time:&lt;/strong&gt; 2–3 minutes&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Shift in 2026
&lt;/h2&gt;

&lt;p&gt;It’s no longer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can you write code fast?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can you start from the right foundation?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI speeds up execution
&lt;/li&gt;
&lt;li&gt;Boilerplates remove setup
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And setup is where most time is lost.&lt;/p&gt;




&lt;h2&gt;
  
  
  When You Should Skip Boilerplates
&lt;/h2&gt;

&lt;p&gt;You don’t need one if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you’re learning auth deeply
&lt;/li&gt;
&lt;li&gt;your project is experimental
&lt;/li&gt;
&lt;li&gt;you enjoy building infra repeatedly
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Otherwise, you’re wasting time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;AI made coding faster.&lt;/p&gt;

&lt;p&gt;But it didn’t solve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;architecture
&lt;/li&gt;
&lt;li&gt;structure
&lt;/li&gt;
&lt;li&gt;system design
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s why boilerplates still win.&lt;/p&gt;

&lt;p&gt;Not because they save minutes.&lt;/p&gt;

&lt;p&gt;Because they remove hours of thinking.&lt;/p&gt;




&lt;h2&gt;
  
  
  Build Faster With a Real Starting Point
&lt;/h2&gt;

&lt;p&gt;If you’re tired of rebuilding auth every time,&lt;br&gt;&lt;br&gt;
start with something that already works.&lt;/p&gt;

&lt;p&gt;👉 Check out &lt;a href="https://buildbasekit.com/" rel="noopener noreferrer"&gt;BuildBaseKit&lt;/a&gt; (ready-to-use backend starters)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auth already set up
&lt;/li&gt;
&lt;li&gt;Clean structure&lt;/li&gt;
&lt;li&gt;RBAC with JWT&lt;/li&gt;
&lt;li&gt;Extend, don’t rebuild
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>backend</category>
      <category>programming</category>
      <category>startup</category>
    </item>
    <item>
      <title>Stop Wasting Weeks on Backend Setup</title>
      <dc:creator>buildbasekit</dc:creator>
      <pubDate>Mon, 13 Apr 2026 16:53:37 +0000</pubDate>
      <link>https://dev.to/buildbasekit/stop-wasting-weeks-on-backend-setup-1b81</link>
      <guid>https://dev.to/buildbasekit/stop-wasting-weeks-on-backend-setup-1b81</guid>
      <description>&lt;p&gt;If you’ve built more than one backend, you’ve seen this before.&lt;/p&gt;

&lt;p&gt;You start a new idea.&lt;/p&gt;

&lt;p&gt;Then you spend days setting up the same things again:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auth&lt;/li&gt;
&lt;li&gt;Roles and permissions&lt;/li&gt;
&lt;li&gt;Multi-tenancy&lt;/li&gt;
&lt;li&gt;Database setup&lt;/li&gt;
&lt;li&gt;Basic APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And suddenly, a week is gone.&lt;/p&gt;

&lt;p&gt;No real product. No users.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real issue
&lt;/h2&gt;

&lt;p&gt;This work isn’t hard.&lt;/p&gt;

&lt;p&gt;It’s repetitive.&lt;/p&gt;

&lt;p&gt;You’re rebuilding solved problems instead of building something people care about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this slows you down
&lt;/h2&gt;

&lt;p&gt;Early stage is about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;shipping fast&lt;/li&gt;
&lt;li&gt;getting feedback&lt;/li&gt;
&lt;li&gt;learning quickly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But instead, most time goes into setup.&lt;/p&gt;

&lt;p&gt;By the time you're ready, momentum is already low.&lt;/p&gt;

&lt;h2&gt;
  
  
  A mistake I kept repeating
&lt;/h2&gt;

&lt;p&gt;On one project, I spent around 10 days just setting up backend basics.&lt;/p&gt;

&lt;p&gt;When I finished, I had nothing to show.&lt;/p&gt;

&lt;p&gt;No users. No feedback.&lt;/p&gt;

&lt;p&gt;That’s when it clicked.&lt;/p&gt;

&lt;p&gt;I wasn’t building a product.&lt;/p&gt;

&lt;p&gt;I was rebuilding infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually matters
&lt;/h2&gt;

&lt;p&gt;You don’t need a perfect backend.&lt;/p&gt;

&lt;p&gt;You need something that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;works&lt;/li&gt;
&lt;li&gt;supports real users&lt;/li&gt;
&lt;li&gt;lets you move fast&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s it.&lt;/p&gt;

&lt;h2&gt;
  
  
  A better approach
&lt;/h2&gt;

&lt;p&gt;Start with a base that already handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;auth&lt;/li&gt;
&lt;li&gt;roles&lt;/li&gt;
&lt;li&gt;structure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then focus on your actual product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reality check
&lt;/h2&gt;

&lt;p&gt;Most developers don’t fail because of bad architecture.&lt;/p&gt;

&lt;p&gt;They fail because they never ship.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;Next time you start a project, don’t ask:&lt;/p&gt;

&lt;p&gt;“What’s the best setup?”&lt;/p&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;p&gt;“How fast can I ship something useful?”&lt;/p&gt;




&lt;p&gt;If you want to skip backend setup and start faster, try this free:&lt;br&gt;&lt;br&gt;
👉 &lt;a href="https://buildbasekit.com/boilerplates/authkit-lite/" rel="noopener noreferrer"&gt;https://buildbasekit.com/boilerplates/authkit-lite/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>saas</category>
      <category>webdev</category>
    </item>
    <item>
      <title>JWT vs Session Authentication in Spring Boot: Which One Should You Use?</title>
      <dc:creator>buildbasekit</dc:creator>
      <pubDate>Thu, 09 Apr 2026 12:07:25 +0000</pubDate>
      <link>https://dev.to/buildbasekit/jwt-vs-session-authentication-in-spring-boot-which-one-should-you-use-4gj5</link>
      <guid>https://dev.to/buildbasekit/jwt-vs-session-authentication-in-spring-boot-which-one-should-you-use-4gj5</guid>
      <description>&lt;p&gt;Most developers pick JWT or sessions based on tutorials or trends.&lt;/p&gt;

&lt;p&gt;That is a mistake.&lt;/p&gt;

&lt;p&gt;The wrong choice can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;break scalability
&lt;/li&gt;
&lt;li&gt;increase complexity
&lt;/li&gt;
&lt;li&gt;create security issues later
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide explains how both actually work in real systems and how to choose the right one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Answer
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;JWT&lt;/strong&gt; for APIs, microservices, and scalable systems
&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;sessions&lt;/strong&gt; for simple server rendered applications
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;JWT is stateless and scalable&lt;br&gt;&lt;br&gt;
Sessions are simpler but harder to scale  &lt;/p&gt;




&lt;h2&gt;
  
  
  When This Decision Matters
&lt;/h2&gt;

&lt;p&gt;You need to choose carefully if you are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;building REST APIs
&lt;/li&gt;
&lt;li&gt;creating login systems
&lt;/li&gt;
&lt;li&gt;scaling across multiple servers
&lt;/li&gt;
&lt;li&gt;deciding between stateless vs stateful architecture
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choosing wrong early creates pain later.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is Session Based Authentication
&lt;/h2&gt;

&lt;p&gt;Session authentication stores user state on the server.&lt;/p&gt;

&lt;h3&gt;
  
  
  How it works:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;server creates a session after login
&lt;/li&gt;
&lt;li&gt;session data is stored on server
&lt;/li&gt;
&lt;li&gt;client sends session ID with each request
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Key characteristics:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;stateful
&lt;/li&gt;
&lt;li&gt;simple to implement
&lt;/li&gt;
&lt;li&gt;tightly coupled to server
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Problem:
&lt;/h3&gt;

&lt;p&gt;Scaling requires shared storage like Redis.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is JWT Authentication
&lt;/h2&gt;

&lt;p&gt;JWT is a stateless authentication method.&lt;/p&gt;

&lt;h3&gt;
  
  
  How it works:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;server generates a token
&lt;/li&gt;
&lt;li&gt;client stores token
&lt;/li&gt;
&lt;li&gt;token is sent with every request
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Key characteristics:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;stateless
&lt;/li&gt;
&lt;li&gt;no server side storage
&lt;/li&gt;
&lt;li&gt;works well across services
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tradeoff:
&lt;/h3&gt;

&lt;p&gt;Token expiration and revocation are harder.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Differences
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Session&lt;/th&gt;
&lt;th&gt;JWT&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;State&lt;/td&gt;
&lt;td&gt;Stateful&lt;/td&gt;
&lt;td&gt;Stateless&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage&lt;/td&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;Client&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scalability&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best For&lt;/td&gt;
&lt;td&gt;Monolith apps&lt;/td&gt;
&lt;td&gt;APIs and microservices&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  When to Use Session Authentication
&lt;/h2&gt;

&lt;p&gt;Use sessions if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you are building server rendered apps
&lt;/li&gt;
&lt;li&gt;your system is small or medium scale
&lt;/li&gt;
&lt;li&gt;you want simple session invalidation
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sessions are easier to manage but not built for scale.&lt;/p&gt;




&lt;h2&gt;
  
  
  When to Use JWT Authentication
&lt;/h2&gt;

&lt;p&gt;Use JWT if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you are building REST APIs
&lt;/li&gt;
&lt;li&gt;frontend and backend are separate
&lt;/li&gt;
&lt;li&gt;you need scalability
&lt;/li&gt;
&lt;li&gt;you are using microservices
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;JWT fits modern backend architecture better.&lt;/p&gt;




&lt;h2&gt;
  
  
  Authentication Flow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Session Flow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;user logs in
&lt;/li&gt;
&lt;li&gt;server creates session
&lt;/li&gt;
&lt;li&gt;session ID stored in cookie
&lt;/li&gt;
&lt;li&gt;server validates session on every request
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  JWT Flow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;user logs in
&lt;/li&gt;
&lt;li&gt;server generates token
&lt;/li&gt;
&lt;li&gt;client stores token
&lt;/li&gt;
&lt;li&gt;token sent with each request
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Example: JWT Filter in Spring Boot
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JwtFilter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;OncePerRequestFilter&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;doFilterInternal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpServletRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                    &lt;span class="nc"&gt;HttpServletResponse&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                    &lt;span class="nc"&gt;FilterChain&lt;/span&gt; &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// extract token&lt;/span&gt;
        &lt;span class="c1"&gt;// validate token&lt;/span&gt;
        &lt;span class="c1"&gt;// set authentication&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;using JWT without handling token expiration&lt;/li&gt;
&lt;li&gt;using sessions in distributed systems without shared storage&lt;/li&gt;
&lt;li&gt;choosing based on trends instead of requirements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These mistakes cause issues in production.&lt;/p&gt;




&lt;h2&gt;
  
  
  Related Guides
&lt;/h2&gt;

&lt;p&gt;If you want implementation details:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://buildbasekit.com/blogs/spring-boot-jwt-authentication/" rel="noopener noreferrer"&gt;https://buildbasekit.com/blogs/spring-boot-jwt-authentication/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For real backend architecture:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://buildbasekit.com/blogs/spring-boot-file-upload-production-guide/" rel="noopener noreferrer"&gt;https://buildbasekit.com/blogs/spring-boot-file-upload-production-guide/&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;There is no universal best option.&lt;/p&gt;

&lt;p&gt;JWT is better for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;APIs&lt;/li&gt;
&lt;li&gt;distributed systems&lt;/li&gt;
&lt;li&gt;scalable backends&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sessions are better for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;simple apps&lt;/li&gt;
&lt;li&gt;quick setups&lt;/li&gt;
&lt;li&gt;server rendered systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choose based on your architecture, not trends.&lt;/p&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is JWT more secure than sessions?
&lt;/h3&gt;

&lt;p&gt;No. Security depends on implementation, not the method.&lt;/p&gt;




&lt;h3&gt;
  
  
  Can JWT be revoked?
&lt;/h3&gt;

&lt;p&gt;Yes, but you need extra mechanisms like token blacklisting.&lt;/p&gt;




&lt;h3&gt;
  
  
  Should I always use JWT for APIs?
&lt;/h3&gt;

&lt;p&gt;Not always. Simpler systems may work better with sessions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Build Faster
&lt;/h2&gt;

&lt;p&gt;If you want a ready to use authentication setup:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://buildbasekit.com/boilerplates/authkit-lite/" rel="noopener noreferrer"&gt;https://buildbasekit.com/boilerplates/authkit-lite/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JWT authentication&lt;/li&gt;
&lt;li&gt;role based access&lt;/li&gt;
&lt;li&gt;clean architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Free and production ready.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>backend</category>
      <category>security</category>
    </item>
    <item>
      <title>How to Store and Serve Files in Spring Boot (Local Storage Guide)</title>
      <dc:creator>buildbasekit</dc:creator>
      <pubDate>Thu, 09 Apr 2026 11:45:48 +0000</pubDate>
      <link>https://dev.to/buildbasekit/how-to-store-and-serve-files-in-spring-boot-local-storage-guide-23id</link>
      <guid>https://dev.to/buildbasekit/how-to-store-and-serve-files-in-spring-boot-local-storage-guide-23id</guid>
      <description>&lt;p&gt;Storing files in Spring Boot using local storage is easy.&lt;/p&gt;

&lt;p&gt;But most implementations break when the project grows.&lt;/p&gt;

&lt;p&gt;What starts as a simple upload API quickly turns into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;messy file paths
&lt;/li&gt;
&lt;li&gt;poor structure
&lt;/li&gt;
&lt;li&gt;scaling issues
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide shows how to implement &lt;strong&gt;local file storage properly&lt;/strong&gt;, so your system stays clean and easy to upgrade later.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Insight
&lt;/h2&gt;

&lt;p&gt;Local storage works well for small to medium applications.&lt;/p&gt;

&lt;p&gt;But it does not scale in distributed systems.&lt;/p&gt;

&lt;p&gt;Use it for simplicity, not long term architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is Local File Storage in Spring Boot
&lt;/h2&gt;

&lt;p&gt;Local storage means saving uploaded files directly on your server filesystem instead of using cloud storage like S3.&lt;/p&gt;

&lt;p&gt;It is simple, fast, and easy to set up.&lt;/p&gt;




&lt;h2&gt;
  
  
  When You Should Use Local Storage
&lt;/h2&gt;

&lt;p&gt;Local storage is a good choice when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;building small to medium applications
&lt;/li&gt;
&lt;li&gt;creating internal tools or admin panels
&lt;/li&gt;
&lt;li&gt;working on MVPs or prototypes
&lt;/li&gt;
&lt;li&gt;running on a single server
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many projects start here. The key is to structure it properly from the beginning.&lt;/p&gt;




&lt;h2&gt;
  
  
  Basic File Storage Flow
&lt;/h2&gt;

&lt;p&gt;A typical file handling flow looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;receive file via upload endpoint
&lt;/li&gt;
&lt;li&gt;validate file
&lt;/li&gt;
&lt;li&gt;save file to local directory
&lt;/li&gt;
&lt;li&gt;store file reference in database
&lt;/li&gt;
&lt;li&gt;serve file via API
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Example: File Upload API
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@PostMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/upload"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;upload&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestParam&lt;/span&gt; &lt;span class="nc"&gt;MultipartFile&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/uploads/"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getOriginalFilename&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;transferTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Uploaded"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works, but it is not production ready yet.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where to Store Files
&lt;/h2&gt;

&lt;p&gt;Do not store files inside your source code folders.&lt;/p&gt;

&lt;p&gt;Instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use a dedicated directory&lt;/li&gt;
&lt;li&gt;make the path configurable&lt;/li&gt;
&lt;li&gt;keep storage separate from your codebase&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/data/uploads/
/var/app/files/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Serving Files Through API
&lt;/h2&gt;

&lt;p&gt;Never expose raw file paths directly.&lt;/p&gt;

&lt;p&gt;Instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create a download endpoint&lt;/li&gt;
&lt;li&gt;stream files instead of loading fully in memory&lt;/li&gt;
&lt;li&gt;set correct content type and headers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This keeps your system secure and efficient.&lt;/p&gt;




&lt;h2&gt;
  
  
  Keep Storage Logic Separate
&lt;/h2&gt;

&lt;p&gt;Avoid putting everything inside controllers.&lt;/p&gt;

&lt;p&gt;Use a clean structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Controller → handles request and response&lt;/li&gt;
&lt;li&gt;Service → handles file logic&lt;/li&gt;
&lt;li&gt;Storage layer → interacts with filesystem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes future migration to S3 much easier.&lt;/p&gt;




&lt;h2&gt;
  
  
  File Naming and Validation
&lt;/h2&gt;

&lt;p&gt;Never trust user input.&lt;/p&gt;

&lt;p&gt;Always:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generate unique file names&lt;/li&gt;
&lt;li&gt;validate file type&lt;/li&gt;
&lt;li&gt;enforce file size limits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bad validation is a common security risk.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Mistakes to Avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;hardcoding file paths&lt;/li&gt;
&lt;li&gt;using original file names directly&lt;/li&gt;
&lt;li&gt;skipping validation&lt;/li&gt;
&lt;li&gt;mixing storage logic with business logic&lt;/li&gt;
&lt;li&gt;serving files without access control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These issues show up later when scaling.&lt;/p&gt;




&lt;h2&gt;
  
  
  When Local Storage is Enough
&lt;/h2&gt;

&lt;p&gt;Local storage is perfectly fine for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;small to medium apps&lt;/li&gt;
&lt;li&gt;internal tools&lt;/li&gt;
&lt;li&gt;prototypes&lt;/li&gt;
&lt;li&gt;single server deployments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But it becomes a limitation when you scale beyond one server.&lt;/p&gt;




&lt;h2&gt;
  
  
  Local Storage vs Cloud Storage
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Local Storage&lt;/th&gt;
&lt;th&gt;Cloud Storage (S3)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;simple setup&lt;/td&gt;
&lt;td&gt;scalable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;low cost&lt;/td&gt;
&lt;td&gt;highly available&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;single server&lt;/td&gt;
&lt;td&gt;distributed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hard to scale&lt;/td&gt;
&lt;td&gt;easy to scale&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you expect growth, design your system so migration is easy.&lt;/p&gt;




&lt;h2&gt;
  
  
  Want Production Ready File Upload?
&lt;/h2&gt;

&lt;p&gt;If you want to move beyond local storage and build a scalable system:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://buildbasekit.com/blogs/spring-boot-file-upload-production-guide/" rel="noopener noreferrer"&gt;https://buildbasekit.com/blogs/spring-boot-file-upload-production-guide/&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Local storage is simple, but it still needs structure.&lt;/p&gt;

&lt;p&gt;If you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;separate concerns&lt;/li&gt;
&lt;li&gt;validate inputs&lt;/li&gt;
&lt;li&gt;design clean APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;you can avoid most common problems and upgrade your system later without rewriting everything.&lt;/p&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Where should I store files in Spring Boot?
&lt;/h3&gt;

&lt;p&gt;Use a dedicated directory outside your source code and make it configurable.&lt;/p&gt;




&lt;h3&gt;
  
  
  Is local storage good for production?
&lt;/h3&gt;

&lt;p&gt;It works for small applications, but not for distributed systems.&lt;/p&gt;




&lt;h3&gt;
  
  
  When should I switch to S3?
&lt;/h3&gt;

&lt;p&gt;When you need scalability, multiple servers, or global access.&lt;/p&gt;




&lt;h2&gt;
  
  
  Related Guides
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://buildbasekit.com/blogs/spring-boot-file-upload-api/" rel="noopener noreferrer"&gt;https://buildbasekit.com/blogs/spring-boot-file-upload-api/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://buildbasekit.com/blogs/file-upload-mistakes-spring-boot/" rel="noopener noreferrer"&gt;https://buildbasekit.com/blogs/file-upload-mistakes-spring-boot/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://buildbasekit.com/blogs/spring-boot-file-upload-production-guide/" rel="noopener noreferrer"&gt;https://buildbasekit.com/blogs/spring-boot-file-upload-production-guide/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://buildbasekit.com/blogs/jwt-mistakes-spring-boot/" rel="noopener noreferrer"&gt;https://buildbasekit.com/blogs/jwt-mistakes-spring-boot/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Build Faster
&lt;/h2&gt;

&lt;p&gt;If you are tired of rebuilding file upload logic:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://buildbasekit.com/boilerplates/filora-fs-lite/" rel="noopener noreferrer"&gt;https://buildbasekit.com/boilerplates/filora-fs-lite/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;file upload system&lt;/li&gt;
&lt;li&gt;local storage setup&lt;/li&gt;
&lt;li&gt;clean architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Free and ready to use.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>backend</category>
      <category>fileupload</category>
    </item>
    <item>
      <title>Spring Boot File Upload: Production Ready System Design Guide</title>
      <dc:creator>buildbasekit</dc:creator>
      <pubDate>Thu, 09 Apr 2026 11:41:18 +0000</pubDate>
      <link>https://dev.to/buildbasekit/spring-boot-file-upload-production-ready-system-design-guide-490l</link>
      <guid>https://dev.to/buildbasekit/spring-boot-file-upload-production-ready-system-design-guide-490l</guid>
      <description>&lt;p&gt;Building a file upload API in Spring Boot is easy.&lt;/p&gt;

&lt;p&gt;Building one that actually works in production is where things break.&lt;/p&gt;

&lt;p&gt;Most developers start with a simple controller and local storage. It works fine until:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;files get large
&lt;/li&gt;
&lt;li&gt;traffic increases
&lt;/li&gt;
&lt;li&gt;security becomes a concern
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide breaks down what actually matters when designing a &lt;strong&gt;production ready file upload system&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Insight
&lt;/h2&gt;

&lt;p&gt;A real file upload system is not just about uploading files.&lt;/p&gt;

&lt;p&gt;You need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;security&lt;/li&gt;
&lt;li&gt;scalable storage&lt;/li&gt;
&lt;li&gt;efficient delivery&lt;/li&gt;
&lt;li&gt;clean API structure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Miss one of these, and things start failing in production.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Problems with Basic File Upload Systems
&lt;/h2&gt;

&lt;p&gt;Most implementations fail because they ignore real world constraints.&lt;/p&gt;

&lt;p&gt;Typical issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;large uploads crash the server
&lt;/li&gt;
&lt;li&gt;no validation leads to security risks
&lt;/li&gt;
&lt;li&gt;local storage fails in distributed setups
&lt;/li&gt;
&lt;li&gt;messy APIs make scaling painful
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have seen any of these, your system is not production ready yet.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. File Upload Security in Spring Boot
&lt;/h2&gt;

&lt;p&gt;Security is not optional.&lt;/p&gt;

&lt;p&gt;Every uploaded file should be treated as untrusted input.&lt;/p&gt;

&lt;h3&gt;
  
  
  What you must do:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;validate file type and size
&lt;/li&gt;
&lt;li&gt;restrict access using authentication (JWT or sessions)
&lt;/li&gt;
&lt;li&gt;never expose internal file paths
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have not set up auth yet, start here:&lt;br&gt;&lt;br&gt;
👉 &lt;a href="https://buildbasekit.com/blogs/spring-boot-jwt-authentication/" rel="noopener noreferrer"&gt;https://buildbasekit.com/blogs/spring-boot-jwt-authentication/&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  2. Scalable File Storage Strategy (S3 and Cloud)
&lt;/h2&gt;

&lt;p&gt;Local storage works only in early stages.&lt;/p&gt;

&lt;p&gt;It breaks when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you scale horizontally
&lt;/li&gt;
&lt;li&gt;you deploy across multiple servers
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Better approach:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;use cloud storage like AWS S3
&lt;/li&gt;
&lt;li&gt;keep storage separate from application logic
&lt;/li&gt;
&lt;li&gt;design storage as a pluggable layer
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gives you flexibility without rewriting your system later.&lt;/p&gt;


&lt;h2&gt;
  
  
  3. File Access and Delivery Optimization
&lt;/h2&gt;

&lt;p&gt;Serving files from your backend is a bottleneck.&lt;/p&gt;
&lt;h3&gt;
  
  
  Production approach:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;use pre signed URLs
&lt;/li&gt;
&lt;li&gt;stream files instead of loading in memory
&lt;/li&gt;
&lt;li&gt;use CDN for faster delivery
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This reduces load on your server and improves performance.&lt;/p&gt;


&lt;h2&gt;
  
  
  4. File Metadata and Management
&lt;/h2&gt;

&lt;p&gt;Uploading files is only half the problem.&lt;/p&gt;

&lt;p&gt;You also need to manage them.&lt;/p&gt;
&lt;h3&gt;
  
  
  Store metadata like:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;file name
&lt;/li&gt;
&lt;li&gt;size
&lt;/li&gt;
&lt;li&gt;owner
&lt;/li&gt;
&lt;li&gt;storage location
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Support:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;listing files
&lt;/li&gt;
&lt;li&gt;deleting files
&lt;/li&gt;
&lt;li&gt;updating metadata
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without this, your system becomes hard to maintain.&lt;/p&gt;


&lt;h2&gt;
  
  
  5. Clean File Upload API Design
&lt;/h2&gt;

&lt;p&gt;Bad API design kills scalability.&lt;/p&gt;
&lt;h3&gt;
  
  
  Keep things separated:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;upload endpoint
&lt;/li&gt;
&lt;li&gt;download endpoint
&lt;/li&gt;
&lt;li&gt;file management endpoints
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Follow clean architecture:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;controller layer
&lt;/li&gt;
&lt;li&gt;service layer
&lt;/li&gt;
&lt;li&gt;storage abstraction
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Avoid mixing responsibilities.&lt;/p&gt;


&lt;h2&gt;
  
  
  Recommended Architecture
&lt;/h2&gt;

&lt;p&gt;A production ready system usually looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Client → Controller → Service → Storage Layer → Cloud (S3)
↓
Database (metadata)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key components:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Controller for request handling
&lt;/li&gt;
&lt;li&gt;Service for business logic
&lt;/li&gt;
&lt;li&gt;Storage abstraction (S3 or local)
&lt;/li&gt;
&lt;li&gt;Database for metadata
&lt;/li&gt;
&lt;li&gt;Authentication layer
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This keeps the system maintainable and scalable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Mistakes to Avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;storing files directly on the app server
&lt;/li&gt;
&lt;li&gt;skipping validation
&lt;/li&gt;
&lt;li&gt;mixing storage logic with business logic
&lt;/li&gt;
&lt;li&gt;serving files without optimization
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These mistakes are the reason most systems fail later.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;A production ready file upload system is not about adding features.&lt;/p&gt;

&lt;p&gt;It is about building the right foundation.&lt;/p&gt;

&lt;p&gt;If you design it properly from the start:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you avoid scaling issues
&lt;/li&gt;
&lt;li&gt;you reduce security risks
&lt;/li&gt;
&lt;li&gt;you save time later
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most developers underestimate this until they hit real world problems.&lt;/p&gt;




&lt;h2&gt;
  
  
  Want a Ready to Use Solution?
&lt;/h2&gt;

&lt;p&gt;If you do not want to rebuild this system again and again:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://buildbasekit.com/boilerplates/filora-fs-pro/" rel="noopener noreferrer"&gt;https://buildbasekit.com/boilerplates/filora-fs-pro/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authentication setup
&lt;/li&gt;
&lt;li&gt;S3 integration
&lt;/li&gt;
&lt;li&gt;clean API structure
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Built for real world applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  Related Guides
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://buildbasekit.com/blogs/spring-boot-file-upload-api/" rel="noopener noreferrer"&gt;https://buildbasekit.com/blogs/spring-boot-file-upload-api/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://buildbasekit.com/blogs/file-upload-mistakes-spring-boot/" rel="noopener noreferrer"&gt;https://buildbasekit.com/blogs/file-upload-mistakes-spring-boot/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://buildbasekit.com/blogs/spring-boot-file-storage-local-guide/" rel="noopener noreferrer"&gt;https://buildbasekit.com/blogs/spring-boot-file-storage-local-guide/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://buildbasekit.com/blogs/how-to-deploy-a-production-ready-file-server-on-a-vps-for-free/" rel="noopener noreferrer"&gt;https://buildbasekit.com/blogs/how-to-deploy-a-production-ready-file-server-on-a-vps-for-free/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>springboot</category>
      <category>backend</category>
      <category>java</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Stop Building Messy Discord Bots in Java</title>
      <dc:creator>buildbasekit</dc:creator>
      <pubDate>Tue, 31 Mar 2026 08:59:54 +0000</pubDate>
      <link>https://dev.to/buildbasekit/stop-building-messy-discord-bots-in-java-5eng</link>
      <guid>https://dev.to/buildbasekit/stop-building-messy-discord-bots-in-java-5eng</guid>
      <description>&lt;p&gt;Building a Discord bot in Java is easy.&lt;/p&gt;

&lt;p&gt;Keeping it clean as it grows is the hard part.&lt;/p&gt;

&lt;p&gt;You start with a few commands, and then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;logic starts mixing with event handling
&lt;/li&gt;
&lt;li&gt;commands become hard to extend
&lt;/li&gt;
&lt;li&gt;small changes break multiple features
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve seen bots become messy very quickly.&lt;/p&gt;

&lt;p&gt;Here’s how to structure it properly from the beginning.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Discord bots become hard to maintain
&lt;/h2&gt;

&lt;p&gt;Most bots start small.&lt;/p&gt;

&lt;p&gt;But as features grow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;commands get tightly coupled with logic
&lt;/li&gt;
&lt;li&gt;event handling becomes inconsistent
&lt;/li&gt;
&lt;li&gt;code duplication increases
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without structure, scaling becomes painful.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Discord Bot Structure Matters for Scalability
&lt;/h2&gt;

&lt;p&gt;When structure is ignored early, even small changes require touching multiple parts of the codebase.&lt;/p&gt;

&lt;p&gt;That’s when development slows down.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;commands become tightly coupled with logic&lt;/li&gt;
&lt;li&gt;event handling becomes inconsistent&lt;/li&gt;
&lt;li&gt;features are harder to extend&lt;/li&gt;
&lt;li&gt;debugging takes longer than expected&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Core Components of a Scalable Discord Bot (Java JDA)
&lt;/h2&gt;

&lt;p&gt;A scalable Discord bot should have clear separation between different responsibilities. Even a simple bot benefits from a structured approach.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;command layer to handle slash commands and inputs&lt;/li&gt;
&lt;li&gt;event listeners to react to Discord events&lt;/li&gt;
&lt;li&gt;service layer for business logic&lt;/li&gt;
&lt;li&gt;configuration layer for environment variables and setup&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How a Discord Bot Works in JDA (Step by Step)
&lt;/h2&gt;

&lt;p&gt;Understanding the flow helps you design a clean and predictable structure.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User triggers a command or event in Discord&lt;/li&gt;
&lt;li&gt;JDA listener receives the event&lt;/li&gt;
&lt;li&gt;Command handler processes input&lt;/li&gt;
&lt;li&gt;Service layer executes logic&lt;/li&gt;
&lt;li&gt;Response is sent back to Discord&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If these responsibilities are not clearly separated, your bot quickly becomes difficult to maintain.&lt;/p&gt;




&lt;h2&gt;
  
  
  Best practice: separate commands and business logic
&lt;/h2&gt;

&lt;p&gt;A common mistake is putting all logic inside command handlers.&lt;/p&gt;

&lt;p&gt;It works at first, but becomes hard to maintain as features grow.&lt;/p&gt;

&lt;p&gt;A better approach is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;commands handle input and response&lt;/li&gt;
&lt;li&gt;services handle actual logic&lt;/li&gt;
&lt;li&gt;listeners react to events independently
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// bad: logic inside command&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CommandEvent&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ping"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Pong"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// business logic mixed here&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Design Your Discord Bot for Scalability and Extension
&lt;/h2&gt;

&lt;p&gt;Your bot should be easy to extend without rewriting existing code. This means organizing features in a modular way.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;group related commands into modules&lt;/li&gt;
&lt;li&gt;keep shared logic reusable&lt;/li&gt;
&lt;li&gt;avoid hardcoded values in logic&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Recommended project structure
&lt;/h2&gt;

&lt;p&gt;This structure keeps your Discord bot modular and easy to scale as features grow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
src/
 ├── commands/
 ├── listeners/
 ├── service/
 ├── config/
 └── utils/

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;If you don’t want to set this up from scratch:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://buildbasekit.com/boilerplates/basely/" rel="noopener noreferrer"&gt;https://buildbasekit.com/boilerplates/basely/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It includes a clean Discord bot structure built with JDA.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common mistakes to avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;putting all code in a single package&lt;/li&gt;
&lt;li&gt;mixing event handling with business logic&lt;/li&gt;
&lt;li&gt;no clear naming or structure for commands&lt;/li&gt;
&lt;li&gt;duplicating logic across different commands&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Common symptom
&lt;/h3&gt;

&lt;p&gt;Adding a new command requires modifying multiple parts of the codebase.&lt;/p&gt;




&lt;h2&gt;
  
  
  Without vs with proper structure
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Without structure
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;logic inside command handlers&lt;/li&gt;
&lt;li&gt;hard to scale features&lt;/li&gt;
&lt;li&gt;duplicate code&lt;/li&gt;
&lt;li&gt;messy event handling&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  With structure
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;clean separation of layers&lt;/li&gt;
&lt;li&gt;easy to extend commands&lt;/li&gt;
&lt;li&gt;reusable logic&lt;/li&gt;
&lt;li&gt;predictable architecture&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Discord bots don’t become complex because of features.&lt;/p&gt;

&lt;p&gt;They become complex because of poor structure.&lt;/p&gt;

&lt;p&gt;If you separate commands, events, and logic early, your bot stays easy to extend as it grows.&lt;/p&gt;




&lt;h2&gt;
  
  
  Want a clean Discord bot setup without rebuilding everything?
&lt;/h2&gt;

&lt;p&gt;I built a minimal Java boilerplate using JDA with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;proper command and event separation
&lt;/li&gt;
&lt;li&gt;clean service layer
&lt;/li&gt;
&lt;li&gt;scalable structure
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;a href="https://buildbasekit.com/boilerplates/basely/" rel="noopener noreferrer"&gt;https://buildbasekit.com/boilerplates/basely/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use it as a starting point instead of building your bot structure from scratch.&lt;/p&gt;




&lt;h2&gt;
  
  
  Related articles
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://buildbasekit.com/blogs/how-to-build-and-deploy-a-java-discord-bot-using-spring-boot/" rel="noopener noreferrer"&gt;How to Build and Deploy a Java Discord Bot Using Spring Boot&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Build a production-ready Discord bot using Java 21, Spring Boot, and JDA. Includes project structure, deployment, and best practices.&lt;/p&gt;




</description>
      <category>java</category>
      <category>springboot</category>
      <category>discordbot</category>
      <category>jda</category>
    </item>
    <item>
      <title>Stop Making These File Upload Mistakes in Spring Boot</title>
      <dc:creator>buildbasekit</dc:creator>
      <pubDate>Tue, 31 Mar 2026 08:43:15 +0000</pubDate>
      <link>https://dev.to/buildbasekit/stop-making-these-file-upload-mistakes-in-spring-boot-2hlb</link>
      <guid>https://dev.to/buildbasekit/stop-making-these-file-upload-mistakes-in-spring-boot-2hlb</guid>
      <description>&lt;p&gt;File upload in Spring Boot looks simple… until it starts breaking.&lt;/p&gt;

&lt;p&gt;At first, it’s just one endpoint.&lt;/p&gt;

&lt;p&gt;Then suddenly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;file logic spreads across your codebase
&lt;/li&gt;
&lt;li&gt;validation is inconsistent
&lt;/li&gt;
&lt;li&gt;storage becomes hard to change
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve seen this turn messy very quickly.&lt;/p&gt;

&lt;p&gt;Here are the most common mistakes and how to avoid them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why file upload implementations go wrong
&lt;/h2&gt;

&lt;p&gt;File upload is deceptively simple.&lt;/p&gt;

&lt;p&gt;But as soon as you add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;validation
&lt;/li&gt;
&lt;li&gt;storage
&lt;/li&gt;
&lt;li&gt;file retrieval
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;the logic starts spreading across multiple layers.&lt;/p&gt;

&lt;p&gt;Without structure, it becomes hard to maintain.&lt;/p&gt;




&lt;h2&gt;
  
  
  How File Upload Works in Spring Boot (Step by Step)
&lt;/h2&gt;

&lt;p&gt;Understanding the flow helps you avoid most implementation mistakes.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Client sends file using multipart request&lt;/li&gt;
&lt;li&gt;Controller receives the file&lt;/li&gt;
&lt;li&gt;Service validates and processes it&lt;/li&gt;
&lt;li&gt;Storage layer saves the file&lt;/li&gt;
&lt;li&gt;API returns file reference or URL&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  1. Mixing file handling logic in controllers
&lt;/h3&gt;

&lt;p&gt;A common mistake is putting file processing directly inside controllers.&lt;/p&gt;

&lt;p&gt;It works at first, but quickly becomes hard to maintain.&lt;/p&gt;

&lt;p&gt;Common issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;file saving logic inside endpoints
&lt;/li&gt;
&lt;li&gt;manual path handling in controllers
&lt;/li&gt;
&lt;li&gt;duplicate logic across APIs
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Controllers should stay thin. File handling belongs in a service layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. No validation for file size and type
&lt;/h2&gt;

&lt;p&gt;Accepting any file without validation can lead to security risks and performance issues.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;uploading extremely large files&lt;/li&gt;
&lt;li&gt;accepting unsupported file types&lt;/li&gt;
&lt;li&gt;no limits configured for uploads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Always define clear limits and validate file types before storing them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recommended Spring Boot File Upload Structure
&lt;/h2&gt;

&lt;p&gt;This structure keeps file upload logic modular and easy to extend as requirements grow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
src/
 ├── controller/
 ├── service/
 ├── storage/
 ├── model/
 └── config/

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;If you don’t want to build this structure from scratch:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://buildbasekit.com/boilerplates/filora-fs-lite/" rel="noopener noreferrer"&gt;https://buildbasekit.com/boilerplates/filora-fs-lite/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It already includes a clean file upload setup with proper separation.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Hardcoding file paths
&lt;/h2&gt;

&lt;p&gt;Hardcoded paths make your application difficult to configure and deploy across environments.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fixed local directories in code&lt;/li&gt;
&lt;li&gt;no environment-based configuration&lt;/li&gt;
&lt;li&gt;difficult to switch storage later&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use configuration properties or environment variables for file storage paths.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common symptom
&lt;/h3&gt;

&lt;p&gt;You start with one upload endpoint and end up debugging file handling issues across multiple parts of your application.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. No clear storage abstraction
&lt;/h2&gt;

&lt;p&gt;Many implementations tightly couple file upload logic with storage details. This makes it hard to switch from local storage to cloud.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;storage logic mixed with upload logic&lt;/li&gt;
&lt;li&gt;no abstraction layer for storage&lt;/li&gt;
&lt;li&gt;difficult to extend to S3 or other providers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A separate storage layer makes your system flexible and easier to maintain.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Ignoring file naming strategy
&lt;/h2&gt;

&lt;p&gt;Saving files with original names can cause conflicts and unexpected overwrites.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;duplicate file names overwrite existing files&lt;/li&gt;
&lt;li&gt;no unique identifiers&lt;/li&gt;
&lt;li&gt;hard to track files reliably&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use unique naming strategies such as UUIDs to avoid collisions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Without vs with proper structure
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Without structure
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;file logic inside controllers&lt;/li&gt;
&lt;li&gt;hardcoded paths&lt;/li&gt;
&lt;li&gt;no validation&lt;/li&gt;
&lt;li&gt;difficult to scale&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  With structure
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;clean separation of layers&lt;/li&gt;
&lt;li&gt;flexible storage system&lt;/li&gt;
&lt;li&gt;proper validation&lt;/li&gt;
&lt;li&gt;easy to maintain&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;File upload is not the problem.&lt;/p&gt;

&lt;p&gt;Bad structure is.&lt;/p&gt;

&lt;p&gt;If you separate responsibilities and handle validation and storage properly, your system stays clean as it grows.&lt;/p&gt;




&lt;h2&gt;
  
  
  Want a clean file upload setup without rebuilding it every time?
&lt;/h2&gt;

&lt;p&gt;I built a minimal Spring Boot boilerplate with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;proper service and storage separation
&lt;/li&gt;
&lt;li&gt;file upload and download endpoints
&lt;/li&gt;
&lt;li&gt;production-ready structure
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;a href="https://buildbasekit.com/boilerplates/filora-fs-lite/" rel="noopener noreferrer"&gt;https://buildbasekit.com/boilerplates/filora-fs-lite/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use it as a starting point instead of reinventing file upload for every project.&lt;/p&gt;




&lt;h2&gt;
  
  
  Related articles
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://buildbasekit.com/blogs/spring-boot-file-upload-api/" rel="noopener noreferrer"&gt;Spring Boot File Upload API (Clean Structure Guide)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Build a Spring Boot file upload API with clean structure. Learn MultipartFile handling, validation, and scalable storage design.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://buildbasekit.com/blogs/how-to-deploy-a-production-ready-file-server-on-a-vps-for-free/" rel="noopener noreferrer"&gt;How to Deploy a Production File Server on a VPS for Free&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Learn how to deploy a scalable file storage backend using Spring Boot. Step by step VPS setup with zero cost.&lt;/p&gt;




</description>
      <category>java</category>
      <category>springboot</category>
      <category>guide</category>
      <category>storage</category>
    </item>
    <item>
      <title>Stop Overcomplicating File Upload in Spring Boot</title>
      <dc:creator>buildbasekit</dc:creator>
      <pubDate>Tue, 31 Mar 2026 08:28:08 +0000</pubDate>
      <link>https://dev.to/buildbasekit/stop-overcomplicating-file-upload-in-spring-boot-g8c</link>
      <guid>https://dev.to/buildbasekit/stop-overcomplicating-file-upload-in-spring-boot-g8c</guid>
      <description>&lt;p&gt;Building a file upload API in Spring Boot looks simple… until it isn’t.&lt;/p&gt;

&lt;p&gt;You start with one endpoint, and suddenly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;file paths are scattered everywhere&lt;/li&gt;
&lt;li&gt;validation is inconsistent&lt;/li&gt;
&lt;li&gt;storage logic leaks into controllers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve seen this turn into a mess very quickly.&lt;/p&gt;

&lt;p&gt;In some cases, teams end up rewriting their entire file handling logic.&lt;/p&gt;

&lt;p&gt;Here’s how to build it clean from the start.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why file upload APIs get messy
&lt;/h2&gt;

&lt;p&gt;File upload starts simple, but complexity grows fast:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;handling different file types&lt;/li&gt;
&lt;li&gt;managing storage paths&lt;/li&gt;
&lt;li&gt;adding validation&lt;/li&gt;
&lt;li&gt;supporting downloads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without structure, this logic spreads across your codebase.&lt;/p&gt;




&lt;h2&gt;
  
  
  Core components of a file upload API
&lt;/h2&gt;

&lt;p&gt;Even a simple setup should include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;upload endpoint to receive files&lt;/li&gt;
&lt;li&gt;download endpoint to retrieve files&lt;/li&gt;
&lt;li&gt;storage layer (local or cloud)&lt;/li&gt;
&lt;li&gt;validation for file size and type&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How Spring Boot File Upload Works (Step by Step)
&lt;/h2&gt;

&lt;p&gt;Understanding the flow helps you design the API correctly from the start.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Client sends file using multipart request&lt;/li&gt;
&lt;li&gt;Controller receives the file&lt;/li&gt;
&lt;li&gt;Service processes and validates it&lt;/li&gt;
&lt;li&gt;Storage layer saves the file&lt;/li&gt;
&lt;li&gt;API returns file reference or URL&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Best Practice: Structure Your Spring Boot File Upload API
&lt;/h2&gt;

&lt;p&gt;One of the biggest mistakes is mixing file handling logic directly into controllers. This makes it harder to change storage strategies later.&lt;/p&gt;

&lt;p&gt;A cleaner approach is to separate responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;controller handles request and response&lt;/li&gt;
&lt;li&gt;service handles file processing logic&lt;/li&gt;
&lt;li&gt;storage layer manages file saving and retrieval&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Recommended project structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
src/
 ├── controller/
 ├── service/
 ├── storage/
 ├── model/
 └── config/

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Common mistakes to avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;storing files without proper naming strategy&lt;/li&gt;
&lt;li&gt;not validating file size or type&lt;/li&gt;
&lt;li&gt;hardcoding file paths&lt;/li&gt;
&lt;li&gt;no separation between upload and storage logic&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  A better approach
&lt;/h2&gt;

&lt;p&gt;Start simple, but keep structure clear from day one.&lt;/p&gt;

&lt;p&gt;This makes it easy to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;switch from local to cloud storage&lt;/li&gt;
&lt;li&gt;add authentication later&lt;/li&gt;
&lt;li&gt;scale without rewriting everything&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Without vs with proper structure
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Without structure
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;file logic inside controllers&lt;/li&gt;
&lt;li&gt;hardcoded paths&lt;/li&gt;
&lt;li&gt;difficult to switch storage&lt;/li&gt;
&lt;li&gt;code duplication&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  With structure
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;clean separation of layers&lt;/li&gt;
&lt;li&gt;easy to extend and maintain&lt;/li&gt;
&lt;li&gt;storage can be swapped&lt;/li&gt;
&lt;li&gt;reusable across projects&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion: Build a Clean File Upload API in Spring Boot
&lt;/h2&gt;

&lt;p&gt;File upload APIs do not need to be complicated. With a simple structure and clear separation of concerns, you can build something that is both easy to maintain and easy to extend.&lt;/p&gt;




&lt;h2&gt;
  
  
  Want a clean file upload setup without rebuilding it every time?
&lt;/h2&gt;

&lt;p&gt;I built a minimal Spring Boot boilerplate with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clean controller, service, and storage separation
&lt;/li&gt;
&lt;li&gt;file upload and download endpoints
&lt;/li&gt;
&lt;li&gt;production-ready structure you can extend
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;a href="https://buildbasekit.com/boilerplates/filora-fs-lite/" rel="noopener noreferrer"&gt;https://buildbasekit.com/boilerplates/filora-fs-lite/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use it as a starting point instead of reinventing file upload for every project.&lt;/p&gt;




&lt;h2&gt;
  
  
  Related articles
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://buildbasekit.com/blogs/file-upload-mistakes-spring-boot/" rel="noopener noreferrer"&gt;Spring Boot File Upload Mistakes (Common Issues)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Avoid common file upload mistakes in Spring Boot. Learn validation, storage design, and how to structure clean file upload APIs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://buildbasekit.com/blogs/how-to-deploy-a-production-ready-file-server-on-a-vps-for-free/" rel="noopener noreferrer"&gt;How to Deploy a Production File Server on a VPS for Free&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Learn how to deploy a scalable file storage backend using Spring Boot. Step by step VPS setup with zero cost.&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>guide</category>
      <category>storgae</category>
    </item>
    <item>
      <title>Stop Making These JWT Mistakes in Spring Boot</title>
      <dc:creator>buildbasekit</dc:creator>
      <pubDate>Tue, 31 Mar 2026 07:15:18 +0000</pubDate>
      <link>https://dev.to/buildbasekit/stop-making-these-jwt-mistakes-in-spring-boot-2g6o</link>
      <guid>https://dev.to/buildbasekit/stop-making-these-jwt-mistakes-in-spring-boot-2g6o</guid>
      <description>&lt;p&gt;Most JWT authentication setups in Spring Boot work... until they don’t.&lt;/p&gt;

&lt;p&gt;You ship fast, everything seems fine, and then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tokens stop validating&lt;/li&gt;
&lt;li&gt;security bugs appear&lt;/li&gt;
&lt;li&gt;your code becomes impossible to maintain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve seen this happen multiple times.&lt;/p&gt;

&lt;p&gt;Here are the most common mistakes and how to avoid them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why JWT mistakes are dangerous
&lt;/h2&gt;

&lt;p&gt;JWT issues are not just bugs.&lt;/p&gt;

&lt;p&gt;They can lead to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;unauthorized access&lt;/li&gt;
&lt;li&gt;broken authentication flows&lt;/li&gt;
&lt;li&gt;hard-to-debug production issues&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fixing structure early saves you from rewriting your auth system later.&lt;/p&gt;




&lt;p&gt;JWT makes authentication easy to scale.&lt;/p&gt;

&lt;p&gt;But a poor implementation quickly turns into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fragile security&lt;/li&gt;
&lt;li&gt;messy code&lt;/li&gt;
&lt;li&gt;hard-to-debug issues&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most problems come from structure, not JWT itself.&lt;/p&gt;




&lt;h2&gt;
  
  
  How JWT authentication actually works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;User logs in with credentials
&lt;/li&gt;
&lt;li&gt;Server generates a signed token
&lt;/li&gt;
&lt;li&gt;Client stores the token
&lt;/li&gt;
&lt;li&gt;Token is sent with every request
&lt;/li&gt;
&lt;li&gt;Server validates before processing
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If any step is poorly implemented, your entire system becomes unreliable.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Mixing authentication logic with business logic
&lt;/h2&gt;

&lt;p&gt;One of the most common mistakes is handling authentication directly inside controllers or services that should focus on business functionality.&lt;/p&gt;

&lt;p&gt;Common issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;token parsing inside controllers&lt;/li&gt;
&lt;li&gt;manual validation scattered across endpoints&lt;/li&gt;
&lt;li&gt;duplicate logic in multiple places&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Authentication should be handled in a dedicated layer, separate from business logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Poor token management
&lt;/h2&gt;

&lt;p&gt;JWT tokens are central to your authentication system. Mismanaging them can lead to serious issues.&lt;/p&gt;

&lt;p&gt;Common symptoms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;users randomly logged out&lt;/li&gt;
&lt;li&gt;expired tokens still accepted&lt;/li&gt;
&lt;li&gt;security vulnerabilities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tokens should be validated consistently and configured with proper expiration strategies.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recommended Spring Boot JWT Authentication Structure
&lt;/h2&gt;

&lt;p&gt;This structure keeps JWT handling isolated and easier to secure and maintain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
src/
 ├── controller/
 ├── service/
 ├── security/
 ├── model/
 └── repository/

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  If you don’t want to build this from scratch:
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://buildbasekit.com/boilerplates/authkit-lite/" rel="noopener noreferrer"&gt;https://buildbasekit.com/boilerplates/authkit-lite/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It includes a clean JWT setup with proper structure and security practices.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Hardcoding secrets and configuration
&lt;/h2&gt;

&lt;p&gt;Storing secrets directly in code is risky and makes your system less secure and harder to manage across environments.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JWT secret keys in source code&lt;/li&gt;
&lt;li&gt;environment-specific values hardcoded&lt;/li&gt;
&lt;li&gt;no use of environment variables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Always use environment-based configuration for sensitive data.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Skipping role-based access control
&lt;/h2&gt;

&lt;p&gt;Authentication alone is not enough. Without proper authorization, your application cannot control what users are allowed to do.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;all endpoints accessible after login&lt;/li&gt;
&lt;li&gt;no role or permission checks&lt;/li&gt;
&lt;li&gt;inconsistent access control logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Role-based access should be part of your authentication design from the beginning.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Overcomplicating the setup
&lt;/h2&gt;

&lt;p&gt;Many implementations introduce unnecessary complexity with multiple filters, configurations, and layers that are difficult to debug.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;too many custom filters without clear purpose&lt;/li&gt;
&lt;li&gt;confusing security configuration&lt;/li&gt;
&lt;li&gt;lack of clear flow for authentication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep the setup simple and structured instead of adding complexity early.&lt;/p&gt;




&lt;h2&gt;
  
  
  Without vs Proper JWT structure
&lt;/h2&gt;

&lt;p&gt;Without structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;auth logic everywhere&lt;/li&gt;
&lt;li&gt;inconsistent validation&lt;/li&gt;
&lt;li&gt;security risks&lt;/li&gt;
&lt;li&gt;hard to scale&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With proper structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clean separation&lt;/li&gt;
&lt;li&gt;centralized token handling&lt;/li&gt;
&lt;li&gt;predictable behavior&lt;/li&gt;
&lt;li&gt;easy to maintain&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Quick checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;keep auth separate from business logic&lt;/li&gt;
&lt;li&gt;use token expiration&lt;/li&gt;
&lt;li&gt;never hardcode secrets&lt;/li&gt;
&lt;li&gt;implement role-based access&lt;/li&gt;
&lt;li&gt;avoid overcomplicating configuration&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;JWT is not the problem.&lt;/p&gt;

&lt;p&gt;Bad structure is.&lt;/p&gt;

&lt;p&gt;If you keep authentication isolated, handle tokens properly, and avoid overengineering, your system will stay clean and secure as it grows.&lt;/p&gt;




&lt;h2&gt;
  
  
  Want a clean JWT setup without the mess?
&lt;/h2&gt;

&lt;p&gt;I built a minimal Spring Boot boilerplate with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;proper security layer separation
&lt;/li&gt;
&lt;li&gt;clean JWT handling
&lt;/li&gt;
&lt;li&gt;role-based access control
&lt;/li&gt;
&lt;li&gt;production-ready structure
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;a href="https://buildbasekit.com/boilerplates/authkit-lite/" rel="noopener noreferrer"&gt;https://buildbasekit.com/boilerplates/authkit-lite/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can use it as a starting point instead of rebuilding auth every time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Related articles
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://buildbasekit.com/blogs/spring-boot-jwt-authentication/" rel="noopener noreferrer"&gt;Spring Boot JWT Authentication (Clean Setup Guide)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Build JWT authentication in Spring Boot with a clean and reusable setup. Learn token handling, security config, and scalable structure.&lt;/p&gt;




</description>
      <category>java</category>
      <category>springboot</category>
      <category>jwt</category>
      <category>security</category>
    </item>
    <item>
      <title>Stop Rewriting JWT Authentication in Spring Boot (Use This Instead)</title>
      <dc:creator>buildbasekit</dc:creator>
      <pubDate>Tue, 31 Mar 2026 06:44:50 +0000</pubDate>
      <link>https://dev.to/buildbasekit/stop-rewriting-jwt-authentication-in-spring-boot-use-this-instead-5465</link>
      <guid>https://dev.to/buildbasekit/stop-rewriting-jwt-authentication-in-spring-boot-use-this-instead-5465</guid>
      <description>&lt;p&gt;If you’ve implemented authentication in Spring Boot more than once,&lt;br&gt;
you’ve probably rebuilt the same setup every time.&lt;/p&gt;

&lt;p&gt;JWT config, Spring Security setup, role handling...&lt;/p&gt;

&lt;p&gt;It gets repetitive fast.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who this is for
&lt;/h2&gt;

&lt;p&gt;This guide is for you if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you’ve implemented auth more than once&lt;/li&gt;
&lt;li&gt;you’re tired of repeating setup&lt;/li&gt;
&lt;li&gt;you want a clean and reusable structure&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Authentication is one of the first things every backend project needs.&lt;/p&gt;

&lt;p&gt;But instead of being a one-time setup, &lt;br&gt;
it often becomes a repeated task.&lt;/p&gt;

&lt;p&gt;The real problem is not authentication itself. &lt;br&gt;
It is the lack of a clean structure and reusable foundation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why authentication becomes messy
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;JWT logic mixed into controllers&lt;/li&gt;
&lt;li&gt;No clear separation of concerns&lt;/li&gt;
&lt;li&gt;Hard to maintain security config&lt;/li&gt;
&lt;li&gt;Different setup in every project&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What a production ready authentication system needs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;User model with roles&lt;/li&gt;
&lt;li&gt;Token generation and validation&lt;/li&gt;
&lt;li&gt;Secure endpoints&lt;/li&gt;
&lt;li&gt;Clear separation of layers&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How to implement JWT authentication (step by step)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Define user model
&lt;/h3&gt;

&lt;p&gt;Create user entity with roles and credentials.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Implement JWT
&lt;/h3&gt;

&lt;p&gt;Handle token generation and validation separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Configure security
&lt;/h3&gt;

&lt;p&gt;Setup filters and authentication providers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Secure endpoints
&lt;/h3&gt;

&lt;p&gt;Apply role-based access control.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Keep logic separate
&lt;/h3&gt;

&lt;p&gt;Do not mix auth with business logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  JWT Authentication in Spring Boot Explained
&lt;/h2&gt;

&lt;p&gt;JWT (JSON Web Token) is a stateless authentication mechanism widely used in Spring Boot applications. &lt;/p&gt;

&lt;p&gt;It allows secure communication between client and server without storing session data.&lt;/p&gt;

&lt;p&gt;In a typical setup, the server generates a token after login. &lt;br&gt;
This token is sent with each request and validated before granting access.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recommended authentication structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
src/
 ├── controller/
 ├── service/
 ├── security/
 ├── model/
 └── repository/

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Common mistakes to avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Auth logic inside controllers&lt;/li&gt;
&lt;li&gt;Hardcoding secrets&lt;/li&gt;
&lt;li&gt;Skipping role checks&lt;/li&gt;
&lt;li&gt;Copy-paste implementations&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How to avoid rebuilding authentication every time
&lt;/h2&gt;

&lt;p&gt;Treat authentication as a reusable module. Use a consistent structure so you can plug it into any project.&lt;/p&gt;

&lt;p&gt;Or instead of building this every time, you can start with a ready setup.&lt;/p&gt;




&lt;h2&gt;
  
  
  Don’t rebuild authentication again
&lt;/h2&gt;

&lt;p&gt;You can implement everything manually&lt;br&gt;&lt;br&gt;
or start with a ready setup.&lt;/p&gt;

&lt;p&gt;AuthKit-Lite includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JWT authentication&lt;/li&gt;
&lt;li&gt;role-based access control&lt;/li&gt;
&lt;li&gt;pre-built APIs&lt;/li&gt;
&lt;li&gt;clean project structure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;a href="https://buildbasekit.com/boilerplates/authkit-lite/" rel="noopener noreferrer"&gt;https://buildbasekit.com/boilerplates/authkit-lite/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Free and open source&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;With the right structure, authentication becomes a one-time effort instead of repeated work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Related articles
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://buildbasekit.com/blogs/jwt-mistakes-spring-boot/" rel="noopener noreferrer"&gt;JWT Mistakes in Spring Boot (Common Issues and Fixes)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Avoid common JWT mistakes in Spring Boot. Learn token validation, security issues, and how to structure authentication properly.&lt;/p&gt;




</description>
      <category>java</category>
      <category>springboot</category>
      <category>jwt</category>
      <category>backend</category>
    </item>
    <item>
      <title>How to Deploy a Production-Ready File Server on a VPS for Free</title>
      <dc:creator>buildbasekit</dc:creator>
      <pubDate>Sun, 22 Mar 2026 13:42:50 +0000</pubDate>
      <link>https://dev.to/buildbasekit/how-to-deploy-a-production-ready-file-server-on-a-vps-for-free-51ld</link>
      <guid>https://dev.to/buildbasekit/how-to-deploy-a-production-ready-file-server-on-a-vps-for-free-51ld</guid>
      <description>&lt;p&gt;This article walks through deploying a self-hosted file server on a VPS with a clean production setup: build the app, configure environment variables, run it with systemd, place Nginx in front, and secure the server with SSL and a firewall.&lt;/p&gt;




&lt;p&gt;Running your own file server is not only about saving on storage costs. It is also about control: you decide where files live, how uploads are handled, what gets exposed publicly, and how the server is secured.&lt;/p&gt;

&lt;p&gt;For this guide, we will use a Spring Boot based file server pattern similar to FiloraFS. The exact app name does not matter much here — the deployment flow is what matters. You can apply these steps to most Java backend file services.&lt;/p&gt;




&lt;h2&gt;
  
  
  What you will build
&lt;/h2&gt;

&lt;p&gt;By the end of this tutorial, you will have a file server that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;accepts file uploads through a backend API&lt;/li&gt;
&lt;li&gt;stores files on disk or in a mounted directory&lt;/li&gt;
&lt;li&gt;runs continuously on a VPS using systemd&lt;/li&gt;
&lt;li&gt;serves traffic through Nginx&lt;/li&gt;
&lt;li&gt;uses HTTPS with a free Let’s Encrypt certificate&lt;/li&gt;
&lt;li&gt;is protected by a basic firewall setup&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A VPS with Ubuntu 22.04 or similar&lt;/li&gt;
&lt;li&gt;Java 21 installed on your local machine and server&lt;/li&gt;
&lt;li&gt;Git access to your project repository&lt;/li&gt;
&lt;li&gt;A domain name, if you want HTTPS with Nginx&lt;/li&gt;
&lt;li&gt;Your application jar built and ready to deploy with FiloraFS-Lite&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.buildbasekit.com/boilerplates/filora-fs-lite/" rel="noopener noreferrer"&gt;Grab source code from here →&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Prepare the application for production
&lt;/h2&gt;

&lt;p&gt;Start by making sure your app has a clean production configuration. Avoid hardcoding secrets or server-specific paths. Use environment variables or a separate production config file instead.&lt;/p&gt;

&lt;p&gt;A typical Spring Boot setup for a file server might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="c"&gt;# application-prod.properties
&lt;/span&gt;&lt;span class="py"&gt;spring.application.name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;filorafs&lt;/span&gt;
&lt;span class="py"&gt;server.port&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;8080&lt;/span&gt;

&lt;span class="py"&gt;storage.local.path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/opt/filora/uploads&lt;/span&gt;
&lt;span class="py"&gt;spring.servlet.multipart.max-file-size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;100MB&lt;/span&gt;
&lt;span class="py"&gt;spring.servlet.multipart.max-request-size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;100MB&lt;/span&gt;

&lt;span class="py"&gt;spring.datasource.url&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;jdbc:mysql://localhost:3306/filorafs&lt;/span&gt;
&lt;span class="py"&gt;spring.datasource.username&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;filora_user&lt;/span&gt;
&lt;span class="py"&gt;spring.datasource.password&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;${DB_PASSWORD}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your project does not use a database, remove the &lt;code&gt;datasource&lt;/code&gt; block and keep only the storage and multipart settings.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Get a free VPS
&lt;/h2&gt;

&lt;p&gt;For a low-cost test deployment, you can use a free-tier VPS from a cloud provider that supports Linux instances. Any machine with public IP access, SSH access, and enough storage for your files will work.&lt;/p&gt;

&lt;p&gt;Once the VPS is ready, download the SSH key or note the login credentials so you can connect securely.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Connect to the server and install dependencies
&lt;/h2&gt;

&lt;p&gt;SSH into the server and install the tools required to run your backend.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-i&lt;/span&gt; your-key.key ubuntu@your-vps-ip

&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;openjdk-21-jdk nginx ufw &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you plan to build the application directly on the server, also install Git and Maven.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;git maven &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Upload the jar and create an app directory
&lt;/h2&gt;

&lt;p&gt;Create a clean folder for your application. Keeping the jar, logs, and environment file inside one directory makes maintenance easier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /opt/filora
&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt;:&lt;span class="nv"&gt;$USER&lt;/span&gt; /opt/filora
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then copy your jar file into that directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;scp target/filorafs.jar ubuntu@your-vps-ip:/opt/filora/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Add environment variables
&lt;/h2&gt;

&lt;p&gt;Put your secrets and server-specific values in a dedicated .env file. This keeps your service config simpler and avoids exposing values in the codebase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="c"&gt;# /opt/filora/.env
&lt;/span&gt;&lt;span class="py"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your_db_password&lt;/span&gt;
&lt;span class="py"&gt;SERVER_PORT&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;8080&lt;/span&gt;
&lt;span class="py"&gt;STORAGE_PATH&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/opt/filora/uploads&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Run the app manually first
&lt;/h2&gt;

&lt;p&gt;Before creating a &lt;code&gt;systemd&lt;/code&gt; service, verify that the jar starts correctly in the terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /opt/filora
&lt;span class="nb"&gt;source&lt;/span&gt; .env
java &lt;span class="nt"&gt;-jar&lt;/span&gt; filorafs.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the application starts without errors, you are ready to make it persistent.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Create a &lt;code&gt;systemd&lt;/code&gt; service
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;systemd&lt;/code&gt; keeps the file server alive after reboot and restarts it automatically if the process crashes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/systemd/system/filorafs.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight systemd"&gt;&lt;code&gt;&lt;span class="k"&gt;[Unit]&lt;/span&gt;
&lt;span class="nt"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;FiloraFS File Server
&lt;span class="nt"&gt;After&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;network.target

&lt;span class="k"&gt;[Service]&lt;/span&gt;
&lt;span class="nt"&gt;User&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;ubuntu
&lt;span class="nt"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;/opt/filora
&lt;span class="nt"&gt;EnvironmentFile&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;/opt/filora/.env
&lt;span class="nt"&gt;ExecStart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;/usr/bin/java -jar /opt/filora/filorafs.jar
&lt;span class="nt"&gt;Restart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;always
&lt;span class="nt"&gt;RestartSec&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;5

&lt;span class="k"&gt;[Install]&lt;/span&gt;
&lt;span class="nt"&gt;WantedBy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;multi-user.target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then enable and start it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl daemon-reload
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;filorafs
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start filorafs
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status filorafs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  8. Put Nginx in front of the app
&lt;/h2&gt;

&lt;p&gt;Nginx is useful even for a simple backend. It gives you a stable public entry point, handles HTTPS termination, and lets you define upload size limits.&lt;/p&gt;

&lt;p&gt;Create a new site config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/nginx/sites-available/filorafs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;yourdomain.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;client_max_body_size&lt;/span&gt; &lt;span class="mi"&gt;100M&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://localhost:8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Real-IP&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt; &lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-Proto&lt;/span&gt; &lt;span class="nv"&gt;$scheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable the site and reload Nginx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /etc/nginx/sites-available/filorafs /etc/nginx/sites-enabled/
&lt;span class="nb"&gt;sudo &lt;/span&gt;nginx &lt;span class="nt"&gt;-t&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  9. Add HTTPS with Let’s Encrypt
&lt;/h2&gt;

&lt;p&gt;If your server is publicly accessible, SSL is not optional. Use Certbot to get a free certificate and let Nginx manage the HTTPS configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;certbot python3-certbot-nginx &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;certbot &lt;span class="nt"&gt;--nginx&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After setup, Certbot can renew certificates automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Lock down the firewall
&lt;/h2&gt;

&lt;p&gt;Use UFW to expose only the ports you actually need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow OpenSSH
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow &lt;span class="s1"&gt;'Nginx Full'&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw &lt;span class="nb"&gt;enable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your backend should never be reached directly, do not expose port 8080 publicly. Let Nginx talk to the app internally on localhost only.&lt;/p&gt;

&lt;h2&gt;
  
  
  11. Test everything
&lt;/h2&gt;

&lt;p&gt;Once the service is live, test upload, download, and delete flows from your browser or API client.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check app logs: &lt;code&gt;journalctl -u filorafs -f&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Check Nginx logs: &lt;code&gt;sudo tail -f /var/log/nginx/error.log&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Confirm HTTPS loads correctly&lt;/li&gt;
&lt;li&gt;Try a real file upload and verify the file appears in your storage directory&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Using localhost in production config
&lt;/h3&gt;

&lt;p&gt;Inside a VPS, localhost is still fine for the app itself, but external clients should connect through your domain and Nginx.&lt;/p&gt;

&lt;h3&gt;
  
  
  Skipping file permissions
&lt;/h3&gt;

&lt;p&gt;Make sure the service user can write to the upload directory, otherwise file storage will fail even if the app starts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exposing the app port directly
&lt;/h3&gt;

&lt;p&gt;Let Nginx handle public traffic and keep the backend private whenever possible.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;A file server becomes much easier to manage once the deployment pattern is clean. Build the jar, move it to a VPS, run it with systemd, place Nginx in front, and secure the machine properly. That is the difference between a demo and a usable production setup.&lt;/p&gt;

&lt;p&gt;If you are using a starter like FiloraFS, this workflow gives you a reliable path from local development to a real deployed service without unnecessary complexity.&lt;/p&gt;




&lt;h3&gt;
  
  
  Original Article
&lt;/h3&gt;

&lt;p&gt;This post was originally published on BuildBaseKit.&lt;/p&gt;

&lt;p&gt;If you prefer reading on the main site or want updates, check it here:&lt;br&gt;&lt;br&gt;
&lt;a href="https://www.buildbasekit.com/blogs/how-to-deploy-a-production-ready-file-server-on-a-vps-for-free/" rel="noopener noreferrer"&gt;https://www.buildbasekit.com/blogs/how-to-deploy-a-production-ready-file-server-on-a-vps-for-free/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Published on March 15, 2026.&lt;/p&gt;

</description>
      <category>guide</category>
      <category>java</category>
      <category>deployment</category>
      <category>springboot</category>
    </item>
  </channel>
</rss>
