We're always looking for ways to improve the developer experience and reduce complexity across your application development pipeline. One way you can use Supabase to do that is with dynamic JavaScript in Edge Functions. This greatly increases the versatility of your edge functions and reduces the need for you to redeploy your functions if you need to change business logic.
Edge Functions in Supabase are serverless functions that execute in response to HTTP requests. These functions are deployed at the edge, meaning they run close to the user's location, resulting in faster response times.
Why Use Dynamic Code Execution?#
Dynamic code execution allows you to modify and run JavaScript code on the fly without having to redeploy your function each time the code changes. This is particularly useful when you need the flexibility to execute different logic depending on the incoming request, without incurring the overhead of redeployment.
Prerequisites#
To follow along, you will need:
- A Supabase project
- Supabase CLI installed on your local machine
- Orb Stack or Docker Desktop installed on your local machine
- Environment variables set up in Vault, ensuring it passes validation in the function (e.g.,
service_role)
Edge Functions defaults to the verification of the JWT, so it could be called with the ANON API Key. Make sure to implement proper security measures.
We have a repo with the SQL script to create helper functions to support the dynamic execution of JavaScript code. You can find the repo here: supa-dynamic
Install the SQL script supa-dynamic--0.1.sql from the repo in your Supabase project. (You can copy and paste the code from the repo into the SQL editor in your Supabase project.)
These are the functions we'll use to execute the JavaScript code:
edge.http_request(url text, method text, headers jsonb, params jsonb, payload jsonb, timeout_ms integer) RETURNS jsonb: Makes an HTTP request with the specified parameters.edge_wrapper(code text) RETURNS text: Executes the provided JavaScript code.edge.get_secret(secret_name text) RETURNS text: Retrieves a secret from Vault.
Deep Dive into the helper functions (optional)#
You can skip this section if you are only interested in using the dynamic execution of JavaScript code. However, if you want to understand how the helper functions work, keep reading.
Function: edge.http_request#
This function handles the actual HTTP request and processes the response. It ensures consistency in response format.
_45 CREATE OR REPLACE FUNCTION edge.http_request( _45 url TEXT, _45 method TEXT DEFAULT 'POST', _45 headers JSONB DEFAULT '{"Content-Type": "application/json"}'::jsonb, _45 params JSONB DEFAULT '{}'::jsonb, _45 payload JSONB DEFAULT '{}'::jsonb, _45 timeout_ms INTEGER DEFAULT 5000 _45 ) RETURNS jsonb AS $$ _45 DECLARE _45 http_response extensions.http_response; _45 status_code integer := 0; _45 response_json jsonb; _45 response_text text; _45 header_array extensions.http_header[]; _45 request extensions.http_request; _45 BEGIN _45 -- Set the timeout option _45 IF timeout_ms > 0 THEN _45 PERFORM http_set_curlopt('CURLOPT_TIMEOUT_MS', timeout_ms::text); _45 END IF; _45 _45 -- Convert headers JSONB to http_header array _45 SELECT array_agg(extensions.http_header(key, value::text)) _45 FROM jsonb_each_text(headers) _45 INTO header_array; _45 _45 -- Construct the http_request composite type _45 request := ROW(method, url, header_array, 'application/json', payload::text)::extensions.http_request; _45 _45 -- Make the HTTP request _45 http_response := http(request); _45 status_code := http_response.status; _45 _45 -- Attempt to extract JSONB response content _45 BEGIN _45 response_json := http_response.content::jsonb; _45 EXCEPTION _45 WHEN others THEN _45 response_text := http_response.content; _45 response_json := jsonb_build_object('status_code', status_code, 'response', response_text); _45 END; _45 _45 RETURN jsonb_build_object('status_code', status_code, 'response', response_json); _45 END; _45 $$ LANGUAGE plpgsql;
Function: edge.edge_wrapper#
The edge_wrapper function manages HTTP requests with features like retries, custom headers, and region selection. Below are the parameters it accepts:
url: The endpoint to call.method: HTTP method, defaulting toPOST.headers: Custom headers to include, including region information.timeout_ms: Timeout duration in milliseconds.max_retries: Maximum retry attempts for the request.
_87 CREATE OR REPLACE FUNCTION edge.edge_wrapper( _87 url TEXT, _87 method TEXT DEFAULT 'POST', _87 headers JSONB DEFAULT '{"Content-Type": "application/json"}'::jsonb, _87 params JSONB DEFAULT '{}'::jsonb, _87 payload JSONB DEFAULT '{}'::jsonb, -- Payload as JSONB _87 timeout_ms INTEGER DEFAULT 5000, _87 max_retries INTEGER DEFAULT 0, _87 allowed_regions TEXT[] DEFAULT NULL _87 ) RETURNS jsonb AS $$ _87 DECLARE _87 retry_count INTEGER := 0; _87 retry_delays DOUBLE PRECISION[] := ARRAY[0, 0.250, 0.500, 1.000, 2.500, 5.000]; _87 succeeded BOOLEAN := FALSE; _87 current_region_index INTEGER := 1; -- Start index at 1 for PostgreSQL array _87 combined_headers JSONB; _87 response_json JSONB; _87 BEGIN _87 -- Validate headers, params, and payload are JSON objects _87 IF headers IS NULL OR NOT jsonb_typeof(headers) = 'object' THEN _87 RAISE EXCEPTION 'Invalid headers parameter: %', headers; _87 END IF; _87 _87 IF params IS NULL OR NOT jsonb_typeof(params) = 'object' THEN _87 RAISE EXCEPTION 'Invalid params parameter: %', params; _87 END IF; _87 _87 IF payload IS NULL OR NOT jsonb_typeof(payload) = 'object' THEN _87 RAISE EXCEPTION 'Invalid payload parameter: %', payload; _87 END IF; _87 _87 -- Validate allowed_regions if provided _87 IF allowed_regions IS NOT NULL AND cardinality(allowed_regions) = 0 THEN _87 RAISE EXCEPTION 'allowed_regions parameter cannot be an empty array'; _87 END IF; _87 _87 -- Check if retry_delays has enough elements _87 IF cardinality(retry_delays) < max_retries + 1 THEN _87 RAISE EXCEPTION 'retry_delays array must have at least % elements', max_retries + 1; _87 END IF; _87 _87 -- Retry loop _87 WHILE NOT succeeded AND retry_count <= max_retries LOOP _87 combined_headers := headers; _87 _87 -- Set x-region header if allowed_regions is provided _87 IF allowed_regions IS NOT NULL AND cardinality(allowed_regions) > 0 THEN _87 combined_headers := combined_headers || jsonb_build_object('x-region', allowed_regions[current_region_index]); _87 END IF; _87 _87 -- Sleep if not the first attempt _87 IF retry_count > 0 THEN _87 PERFORM pg_sleep(retry_delays[retry_count]); _87 END IF; _87 _87 retry_count := retry_count + 1; _87 _87 -- Increment region index, wrapping around if necessary _87 IF allowed_regions IS NOT NULL AND cardinality(allowed_regions) > 0 THEN _87 current_region_index := current_region_index + 1; _87 IF current_region_index > cardinality(allowed_regions) THEN _87 current_region_index := 1; _87 END IF; _87 END IF; _87 _87 BEGIN _87 RAISE WARNING 'headers:%s', combined_headers; _87 _87 -- Call the simplified HTTP request function _87 response_json := edge.http_request(url, method, combined_headers, params, payload, timeout_ms); _87 _87 -- Check the status code _87 IF (response_json->>'status_code')::INTEGER < 500 THEN _87 succeeded := TRUE; _87 END IF; _87 EXCEPTION _87 WHEN OTHERS THEN _87 IF retry_count > max_retries THEN _87 RAISE EXCEPTION 'HTTP request failed after % retries. SQL Error: { %, % }', _87 max_retries, SQLERRM, SQLSTATE; _87 END IF; _87 END; _87 END LOOP; _87 _87 RETURN response_json; _87 END; _87 $$ LANGUAGE plpgsql;
To securely manage secrets, you will need to set your service_role_key in Vault. Here’s how you can create a function to retrieve secrets:
_17 CREATE OR REPLACE FUNCTION edge.get_secret(secret_name text) RETURNS text _17 LANGUAGE "plpgsql" _17 AS $$ _17 DECLARE _17 decrypted text; _17 BEGIN _17 IF current_setting('request.jwt.claims', true)::jsonb->>'role' = 'service_role' OR current_user = 'postgres' THEN _17 SELECT decrypted_secret _17 INTO decrypted _17 FROM vault.decrypted_secrets _17 WHERE name = secret_name; _17 RETURN decrypted; _17 ELSE _17 RAISE EXCEPTION 'Access denied: only service_role or postgres user can execute this function.'; _17 END IF; _17 END; _17 $$;
This function can retrieve the service_role secret from Vault, it also ensures that only authorized roles can access sensitive environment variables.
Let's dive into the code and set up our dynamic JavaScript executor Edge Function using Deno. Below is an overview of how to accomplish this.
Code Walkthrough#
We'll create a function named multi-purpose:
_10 supabase functions new multi-purpose
Now, we'll edit the code adding verification and the eval function, including the supabase client so we have it ready without the need to import.
_44 import "jsr:@supabase/functions-js/edge-runtime.d.ts"; _44 _44 // Import the supabase client _44 import { createClient } from "<https://esm.sh/@supabase/supabase-js@2>"; _44 _44 console.log("===\\n\\tBooted Edge Worker!\\n===\\n"); _44 const supabase_url = Deno.env.get("SUPABASE_URL") ?? ""; _44 const service_role = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY"); _44 // Set the permission to service_role key: _44 const supabase = createClient(supabase_url, service_role); _44 // This allows us to use Supabase.ai in the function _44 const session = new Supabase.ai.Session('gte-small'); _44 _44 Deno.serve(async (req: Request) => _44 const authorization = req.headers.get("Authorization"); _44 if (!authorization) throw new Error("Authorization header is missing."); _44 // Ensures that the function is called with service_role to prevent missuse _44 if (!authorization.includes(service_role)) { _44 throw new Error("Authorization header is invalid."); _44 } _44 _44 const { code } = await req.json(); _44 try { _44 // Wrap the provided code in an async function context _44 const asyncFunction = new Function('supabase', ` _44 return (async () => { _44 ${code.replace(/\\\\/g, '')} _44 })(); _44 `); _44 // Pass the Supabase client as the scope for the function to use: _44 const data = await asyncFunction(supabase); _44 console.log(data); _44 return new Response( _44 JSON.stringify({ data }), _44 { headers: { 'Content-Type': 'application/json', 'Connection': 'keep-alive' } }, _44 ); _44 } catch (error) { _44 console.error("Error executing user code:", error); _44 return new Response( _44 JSON.stringify({ error: "An error occurred -> " + error.message }), _44 { status: 500, headers: { "Content-Type": "application/json" } } _44 ); _44 } _44 });
Note: If you need more details, check the full guide to create an edge function.
Step-by-Step Walkthrough#
- Validate Authorization: First, we ensure the request contains a valid authorization header. (this prevents calls from anon users)
_10 const authorization = req.headers.get('Authorization') _10 if (!authorization) throw new Error('Authorization header is missing.') _10 // Ensures that the function is called with service_role to prevent missuse _10 if (!authorization.includes(service_role)) { _10 throw new Error('Authorization header is invalid.') _10 }
- Receive JavaScript Code Payload: Extract the
codefrom the request body.
_10 const { code } = await req.json()
- Wrap Code in Async Context: Use
new Function()to create an async function that executes the incoming JavaScript code. This allows async calls in the code to be executed:
_10 try { _10 // Wrap the provided code in an async function context _10 const asyncFunction = new Function('supabase', ` _10 return (async () => { _10 ${code.replace(/\\\\/g, '')} _10 })(); _10 `); _10 }
- Execute and Return Results: Run the JavaScript code, which can interact with Supabase via the provided client, and return the results.
_10 // Pass the Supabase client as the scope for the function to use: _10 const data = await asyncFunction(supabase) _10 console.log(data) _10 return new Response(JSON.stringify({ data }), { _10 headers: { 'Content-Type': 'application/json', Connection: 'keep-alive' }, _10 })
Deploying the Edge Function#
To deploy this Edge Function, you'll need to use the Supabase CLI. Ensure you have Docker installed and running on your local machine. Follow these steps to deploy:
- Install the Supabase CLI: If you haven't already, install the Supabase CLI by following the instructions in the Supabase CLI Documentation.
- Log In to Supabase: Use the command
supabase loginto authenticate your account. - Deploy the Function: Run the command
supabase functions deploy <function_name>to deploy your Edge Function. Replace<function_name>with the desired name for your function.
Setting Environment Variables in Vault#
Creating the main function to interact with the edge function#
We are using the helper functions defined earlier to create a function that interacts with the edge function. This function will execute the dynamic JavaScript code and return the results. This is the main function that will be used to execute the dynamic JavaScript code and return the results.
edge.exec Function#
The edge.exec is a simple function leverages edge_wrapper to execute dynamic JavaScript code. Here's an example of how it is structured:
_23 CREATE OR REPLACE FUNCTION edge.exec(data text) RETURNS JSONB LANGUAGE plpgsql _23 AS $function$ _23 DECLARE _23 custom_headers JSONB; _23 -- Example restricting regions available to Europe _23 allowed_regions TEXT[] := ARRAY['eu-west-1', 'eu-west-2', 'eu-west-3', 'eu-north-1', 'eu-central-1']; _23 BEGIN _23 -- Set headers with anon key and Content-Type _23 custom_headers := jsonb_build_object( _23 'Authorization', 'Bearer ' || edge.get_secret('service_role_key'), _23 'Content-Type', 'application/json', _23 'x-region', allowed_regions _23 ); _23 -- Call edge_wrapper function with default values _23 RETURN edge.edge_wrapper( _23 url := ('https://<ref>.supabase.co/functions/v1/multi-purpose'), _23 headers := custom_headers, _23 payload := jsonb_build_object('code', data), _23 max_retries := 5, _23 allowed_regions := allowed_regions _23 ); _23 END; _23 $function$;
Executing Dynamic JavaScript Code#
The key to executing the dynamic JavaScript code is wrapping it in an async function context using new Function(). This approach lets you evaluate the code in isolation while retaining access to the supabase client for interacting with your database. You can check the examples of how to use this calling the supabase client or even generating embeddings.
Example of Using Supabase Client Libraries#
To demonstrate the execution of dynamic JavaScript, you can use the Supabase client libraries within the SQL context. Here’s an example query:
_12 SELECT edge.exec( _12 $js$ _12 const { data, error } = await supabase.rpc('postgres_function', {'foo': 'bar'}); _12 if (error) { _12 return new Response(JSON.stringify({ error: "An error occurred ->" + error.message }), { _12 status: 500, _12 headers: { "Content-Type": "application/json" }, _12 }); _12 } _12 return data; _12 $js$ _12 );
Example: Generating Embeddings#
The edge.exec function allows for dynamic JavaScript execution, such as interacting with an AI session to generate embeddings. When executed, the JavaScript code within the SQL context runs through the edge function, returning results to the database.
_10 select edge.exec( _10 $js$ _10 _10 const session = new Supabase.ai.Session('gte-small'); _10 return await session.run('hello world'); _10 _10 $js$);
You can also create a Postgres function to generate embeddings:
_22 CREATE OR REPLACE FUNCTION edge.generate_embedding(input_text TEXT) RETURNS JSONB AS $$ _22 DECLARE _22 response JSONB; _22 BEGIN _22 -- Call the edge function to generate the embedding for the provided text _22 response := edge.exec( _22 format( _22 $js$ _22 const session = new Supabase.ai.Session('gte-small'); _22 return await session.run(%L); _22 $js$, _22 input_text _22 ) _22 ); _22 RETURN response->'response'->'data'; _22 END; _22 $$ LANGUAGE plpgsql; _22 _22 select edge.generate_embedding('The quick brown fox jumps over the lazy dog'); _22 _22 -- response: _22 -- [-0.07254139333963394,-0.02173878252506256,0.042930446565151215,0.04853367060422897,0.015609614551067352,0.02912059798836708,0.0371023565530777,0.05054798722267151,0.0035842431243509054,0.0015563230263069272,0.0009484672918915749,-0.09247169643640518,0.04190639406442642,0.05874202027916908,-0.012341015040874481,0.01661474071443081,-0.013452880084514618,0.003742767730727792,-0.07664268463850021,0.03231268376111984,0.0006968052475713193,-0.06508929282426834,-0.04956015944480896,-0.014327225275337696,0.03270547464489937,0.01635774038732052,-0.022707758471369743,-0.007586371619254351,-0.03548099845647812,-0.17844657599925995,0.03325255215167999,-0.07009242475032806,0.02982083335518837,-0.05649203434586525,-0.006693259347230196,-0.02781110256910324,-0.01687553897500038,0.04976152256131172,-0.015715090557932854,0.038247860968112946,0.040495794266462326,-0.007263457402586937,-0.019288228824734688,-0.0527581050992012,-0.0065462407656013966,-0.022786622866988182,-0.04975651577115059,-0.04053974151611328,0.03047902137041092,-0.05064946785569191,-0.023929744958877563,-0.03891737014055252,0.03785012289881706,-0.0133274607360363,0.03001898154616356,-0.007281183265149593,0.060004156082868576,0.017414024099707603,0.025516854599118233,0.029599720612168312,0.02893918938934803,0.03455337509512901,-0.14698833227157593,0.09387505799531937,0.05768263339996338,0.019130567088723183,-0.0380706787109375,-0.04105521738529205,0.008963614702224731,0.012743324972689152,0.009223062545061111,0.060711149126291275,0.007398003712296486,0.04229794815182686,0.046996768563985825,-0.003397924592718482,0.00808036606758833,0.022617157548666,-0.01847437582910061,0.0026343590579926968,-0.010598739609122276,-0.037673674523830414,-0.04375630244612694,-0.0007789010996930301,-0.007935777306556702,-0.03272915259003639,0.021433845162391663,-0.07967976480722427,0.06888656318187714,0.07489841431379318,-0.02783842757344246,-0.006374717690050602,-0.035476282238960266,0.006344574969261885,-0.03357071802020073,-0.036727335304021835,0.012309364043176174,-0.00006389369809767231,-0.053050097078084946,0.19709722697734833,-0.05575009435415268,0.05757850036025047,0.0951322615146637,-0.04633559286594391,0.03476420044898987,0.012983368709683418,0.0004390157700981945,0.010212302207946777,-0.012741461396217346,0.014706282876431942,0.03321540355682373,-0.006495281588286161,0.041682176291942596,0.003406582633033395,0.02581774815917015,-0.0007246752502396703,0.011133069172501564,0.08353550732135773,0.006477882619947195,0.00224463758058846,0.020395604893565178,-0.013416256755590439,0.05663946643471718,-0.028388522565364838,0.019082417711615562,-0.08387858420610428,0.054498571902513504,0.10694538056850433,0.06286843866109848,0.03180928900837898,0.037740662693977356,-0.07479764521121979,0.010231229476630688,-0.04866624251008034,0.004061027429997921,0.0362103171646595,-0.009540606290102005,0.00915283989161253,0.031154874712228775,-0.04876647889614105,-0.015956921502947807,-0.1429857611656189,-0.01470054779201746,-0.09399641305208206,-0.019157350063323975,0.02896934375166893,-0.018669532611966133,0.014991801232099533,-0.06764508783817291,0.027312103658914566,-0.003859955817461014,0.025718173012137413,-0.018675100058317184,-0.016409857198596,-0.021459592506289482,0.004702075384557247,-0.0323822982609272,0.10394860059022903,-0.020106177777051926,-0.008876764215528965,-0.027185838669538498,0.0003392586368136108,-0.009877108968794346,-0.0004303457390051335,0.04185814782977104,-0.05188998952507973,-0.021185973659157753,0.00026368125691078603,-0.02180171199142933,-0.03400561958551407,0.020068379119038582,0.034275852143764496,-0.10943055897951126,0.031987469643354416,0.054017845541238785,-0.009243185631930828,-0.07103140652179718,0.00785127654671669,-0.0040434580296278,-0.05036382004618645,0.07858535647392273,-0.08356015384197235,-0.06914680451154709,0.06180981919169426,0.043073058128356934,-0.020246226340532303,-0.015496478416025639,-0.005946696270257235,0.006562687456607819,0.04845070466399193,-0.029123008251190186,0.02194702997803688,0.002446065191179514,-0.06825454533100128,-0.07056894898414612,0.01598423719406128,-0.04185032472014427,-0.01633128523826599,0.014294272288680077,-0.01768324337899685,0.05590462312102318,-0.044063832610845566,0.02461099997162819,0.0006756667862646282,0.07429251074790955,0.011551265604794025,0.014212443493306637,-0.02237367257475853,0.039057254791259766,0.000325449975207448,-0.004185846075415611,-0.003040974261239171,0.01800958439707756,-0.02479490265250206,-0.019247515127062798,0.04366869106888771,-0.027130864560604095,0.018955133855342865,0.03239727392792702,0.03226468712091446,0.06487660109996796,-0.06456360220909119,0.0006639647181145847,-0.20788206160068512,0.05066373199224472,-0.012870946899056435,-0.034873317927122116,0.023824242874979973,-0.02305314689874649,0.030056791380047798,-0.06937119364738464,0.0642433762550354,0.05418730527162552,0.06050065532326698,-0.04655877873301506,-0.026898164302110672,-0.003803820814937353,0.002598312683403492,0.1081414744257927,0.014850604347884655,0.013619652017951012,0.013523285277187824,-0.0016119466163218021,-0.00329813570715487,0.002907108049839735,0.014589778147637844,-0.048919934779405594,0.056754376739263535,-0.03171522915363312,0.2308642566204071,0.08356188982725143,0.05350973457098007,-0.03191335126757622,0.003732810029760003,0.031172126531600952,-0.08899383991956711,-0.09938952326774597,0.08256369829177856,0.08178982138633728,0.07785400003194809,-0.04618730768561363,-0.02995850332081318,-0.022348755970597267,-0.05898110195994377,0.05294518917798996,0.0038859194610267878,-0.0923057422041893,-0.01576364040374756,-0.0035308743827044964,-0.04901731014251709,-0.012596397660672665,-0.036502618342638016,0.00886201299726963,0.059619251638650894,-0.017561428248882294,0.05459151417016983,0.04560315981507301,-0.0019153780303895473,0.009595169685781002,-0.057729125022888184,0.026341130957007408,-0.023892194032669067,0.016832968220114708,-0.026450062170624733,-0.07305766642093658,0.03468620404601097,-0.02054707705974579,0.041034333407878876,0.00404499564319849,-0.017474710941314697,-0.043891143053770065,0.02514275535941124,0.02372695878148079,0.010677577927708626,0.06225359067320824,0.040919024497270584,0.005154050886631012,0.030111495405435562,0.0054080006666481495,0.03592434898018837,0.0001651789789320901,0.017304912209510803,-0.01922907680273056,0.04822206869721413,-0.0688890889286995,0.019858958199620247,-0.0008752745925448835,0.03513675928115845,-0.07729781419038773,0.08145932108163834,-0.0327017717063427,0.03425054997205734,-0.08482713997364044,0.006879036780446768,0.059308722615242004,-0.03618019446730614,-0.056978799402713776,-0.021730659529566765,-0.0007874490693211555,-0.30017349123954773,0.011467894539237022,0.0029629627242684364,-0.00585860526189208,-0.010300826281309128,0.023507587611675262,0.009586751461029053,0.01615791581571102,-0.05407087132334709,-0.0025957857724279165,-0.005770532879978418,0.03627054765820503,0.03723520413041115,0.0002953026269096881,-0.01028500497341156,0.003999052103608847,-0.005846572108566761,0.033623822033405304,-0.0072589460760355,-0.07468357682228088,0.03272583335638046,-0.00448765279725194,0.21248994767665863,-0.057705674320459366,0.044046953320503235,0.03008623979985714,-0.018218697980046272,0.04393533617258072,0.07603447884321213,-0.04150347039103508,0.06695082038640976,-0.010416779667139053,0.08510852605104446,-0.07743050903081894,-0.005964982323348522,0.03540671616792679,-0.036865249276161194,0.058287233114242554,0.005791360046714544,-0.03530560061335564,-0.010620728135108948,0.03216135874390602,0.012065712362527847,-0.05922657623887062,0.08696120232343674,-0.051534030586481094,-0.08612160384654999,-0.04676511138677597,-0.005788259673863649,0.06060168892145157,-0.02552523836493492,-0.02923434041440487,-0.05256013199687004,0.0033684736117720604,0.023232899606227875,0.023369308561086655,-0.02598796784877777,-0.02167469449341297,-0.05872185155749321,-0.0459195151925087,0.008857548236846924,-0.07634632289409637,0.016223475337028503,0.03924580290913582,0.11316763609647751]
Example: Creating Users via Admin API#
You can also leverage the admin API to create users:
_10 select edge.exec( _10 $js$ _10 _10 const { data, error } = await supabase.auth.admin.createUser({ _10 email: 'user@email.com', _10 password: 'password', _10 user_metadata: { name: 'Yoda' } _10 }); _10 _10 $js$));
As you can see, combining dynamic Javascript in Edge Functions with a few SQL support functions gets you a powerful new set of tools. By leveraging the edge_wrapper, edge.http_request, and edge.exec functions, developers can create robust and flexible serverless applications that can dynamically execute JavaScript code while interacting with PostgreSQL databases.
As we continue to build and innovate with Supabase, combining edge functions and SQL support functions opens up new avenues for building scalable, efficient, and secure applications. Whether developing a simple project or a complex application, these tools provide the flexibility and power to bring your ideas to life.