Creating a Svelte Flask app on vercel

Hey, I’m having trouble deploying Svelte and Flask in the same app.
I’m an experienced data engineer but very new to anything that touches front end, especially making front end and backend talk to each other.
I’ve got my app working locally, with flask and svelte both spun up in different terminals, and I’ve got it deployed and running without 404, but I can’t get my app to talk to each other, getting 500 errors, and it seems like my flask app isn’t receiving anything.

How can I fix this, or at least can I confirm that flask is running in vercel?
I’ve tried a lot of variations on my vercel.json, and am not sure where my issue is stemming from. I’ll attach a lot of detail on my code to help, sorry that it is a lot.

And generally, I want to run svelte, flask, with a sqlite db. If the sqlite db isn’t advisable, the best practice to keep persistent storage on a small mb level of data would be appreciated.

Here is my project structure


├── README.md
├── __pycache__
│   └── config.cpython-39.pyc
├── app
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-39.pyc
│   │   ├── models.cpython-39.pyc
│   │   └── schemas.cpython-39.pyc
│   ├── models.py
│   ├── routes
│   │   ├── __init__.py
│   │   ├── __pycache__
│   │   ├── drills.py
│   │   └── practice_plans.py
│   └── schemas.py
├── config.py
├── cypress
│   ├── downloads
│   ├── e2e
│   │   └── drill_creation.cy.js
│   ├── fixtures
│   │   └── example.json
│   └── support
│       ├── commands.ts
│       └── e2e.ts
├── cypress.config.js
├── instance
│   └── app.db
├── jsconfig.json
├── migrations
│   ├── README
│   ├── __pycache__
│   │   └── env.cpython-39.pyc
│   ├── alembic.ini
│   ├── env.py
│   ├── script.py.mako
│   └── versions
│       ├── __pycache__
│       └── d619d994ebdc_.py
├── package-lock.json
├── package.json
├── playwright.config.js
├── pnpm-lock.yaml
├── requirements.txt
├── src
│   ├── app.d.ts
│   ├── app.html
│   ├── lib
│   │   ├── images
│   │   └── vitals.js
│   └── routes
│       ├── +layout.server.js
│       ├── +layout.svelte
│       ├── +page.js
│       ├── +page.svelte
│       ├── Counter.svelte
│       ├── Header.svelte
│       ├── api
│       ├── drills
│       ├── practice-plans
│       └── styles.css
├── static
│   ├── favicon.png
│   └── robots.txt
├── svelte.config.js
├── tests
│   ├── test.js
│   └── test_api.py
├── tsconfig.json
├── vercel.json
└── vite.config.js

Here are some file snippets:
app/init.py


app = Flask(__name__)
app.config.from_object('config.Config')

db = SQLAlchemy(app)
ma = Marshmallow(app)
migrate = Migrate(app, db)

CORS(app)

from app.routes.drills import drills_bp
from app.routes.practice_plans import practice_plans_bp

app.register_blueprint(drills_bp, url_prefix='/api/drills')
app.register_blueprint(practice_plans_bp, url_prefix='/api/practice-plans')

app/routes/init.py

(Some duplication here, but shouldn’t cause issues, and doesn’t locally)

from flask import Blueprint

main_bp = Blueprint('main', __name__)

def register_blueprints(app):
    from app.routes.drills import drills_bp
    from app.routes.practice_plans import practice_plans_bp

    app.register_blueprint(drills_bp, url_prefix='/api/drills')
    app.register_blueprint(practice_plans_bp, url_prefix='/api/practice-plans')

app/routes/drills.py


drills_bp = Blueprint('drills', __name__)

@drills_bp.route('/', methods=['POST'])
def create_drill():

And src/routes/api/drills/+server.js

import { json } from '@sveltejs/kit';

   const API_BASE_URL = 'http://127.0.0.1:5000';

   export async function POST({ request }) {
       const drill = await request.json();

and

vercel.json

{
  "rewrites": [
    { "source": "/api/drills/(.*)", "destination": "/api/drills" },
    { "source": "/api/practice-plans/(.*)", "destination": "/api/practice-plans" }
  ]
}

And I’m getting 500 errors whenever I try to use the flask backend.

Error occurred while sending request: TypeError: fetch failed
    at node:internal/deps/undici/undici:13178:13
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async POST (file:///var/task/.svelte-kit/output/server/entries/endpoints/api/drills/_server.js:9:22)
    at async render_endpoint (file:///var/task/.svelte-kit/output/server/index.js:214:20)
    at async resolve2 (file:///var/task/.svelte-kit/output/server/index.js:3495:22)
    at async respond (file:///var/task/.svelte-kit/output/server/index.js:3384:22)
    at async Server.default (file:///var/task/.svelte-kit/vercel-tmp/index.js:47:3)
    at async Server.<anonymous> (/opt/rust/nodejs.js:8:4242) {
  [cause]: Error: connect ECONNREFUSED 127.0.0.1:5000
      at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1607:16)
      at TCPConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) {
    errno: -111,
    code: 'ECONNREFUSED',
    syscall: 'connect',
    address: '127.0.0.1',
    port: 5000
  }
}

Hi, @austeane!

Thanks for taking the time to share details of your project. I’d need a bit more time to look through this, but wanted to share some resources in case they’re helpful:

I’m also curious your choice of Svelte and Flask? I wonder if you could simplify this even more. :thinking: Maybe something like:

You could transition from a separate Flask backend and Svelte frontend to an integrated SvelteKit app. Instead of using Flask for the backend, you’ll leverage SvelteKit’s built-in API routes to handle server-side logic. This eliminates the need for a separate Flask server.

You’ll also need to switch from SQLite to a serverless-compatible database solution, such as Vercel Postgres or Vercel KV, as SQLite requires a persistent filesystem that isn’t available in serverless environments.

Let me know what you think!

Thank you, I will take a look at doing sveltekit instead of flask on the back end.
I would still like help getting svelte and flask running together because I am more comfortable in python on the backend.
On a related note, I tried the vercel and flask template, but it doesn’t work at all, it breaks in the initial build. Next.js Flask Starter – Vercel

1 Like

Thanks for reporting! I’ll share it internally. :smile: