100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Your First F# Program

A walkthrough of scaffolding, understanding, and running a basic F# console application, from Program.fs to dotnet run.

FoundationsBeginner7 min readJul 10, 2026
Analogies

Your First F# Program

The traditional way to start an F# project is dotnet new console -lang "F#" -o HelloFSharp, which scaffolds a minimal console application containing a single file, Program.fs, along with a .fsproj project file that tells the .NET build system which source files to compile and in what order. Unlike many languages, F# compiles files top-to-bottom and depends on their order in the .fsproj, so understanding that file matters even for a simple 'Hello, World!' program.

🏏

Cricket analogy: The .fsproj dictating file compile order is like a batting order sheet handed to the umpire before the match — who comes to the crease, and in what sequence, is fixed before play starts.

Understanding Program.fs

Inside Program.fs, the generated template defines a main function decorated with the [<EntryPoint>] attribute, which tells the compiler this is where program execution begins — much like Main in C# or main in C. The function must accept a string array of command-line arguments and return an int exit code (0 conventionally means success); inside it, printfn "Hello, World!" writes text to the console, where printfn is F#'s type-safe formatted-print function, using placeholders like %s for strings, %d for integers, and %f for floats, all checked by the compiler at compile time.

🏏

Cricket analogy: [<EntryPoint>] marking where execution starts is like the toss deciding which team bats first — a single, unambiguous designated starting point for the whole match.

Running with dotnet run vs F# Interactive

You can run the program two ways: dotnet run from the project folder compiles the whole project and executes the resulting binary, which is the standard workflow for a real application; alternatively, for quick experiments you can skip the project entirely and write a .fsx script file, then execute it directly with dotnet fsi hello.fsx, which is faster for throwaway exploration since there's no project file or build step involved, just the F# Interactive engine interpreting the script.

🏏

Cricket analogy: Running dotnet fsi hello.fsx for quick experiments versus dotnet run for the real project is like a net session for trying a new shot versus stepping out to bat in an actual first-class match.

Building a Slightly Bigger Example

A slightly richer first program demonstrates more of F#'s character than a bare 'Hello, World!': defining a small helper function above main, calling it with a list of names, and printing a formatted greeting for each one shows function definition, list iteration with List.iter, and printfn's multiple format specifiers working together in a single small file — a realistic taste of how F# code is typically structured even in much larger programs.

🏏

Cricket analogy: Iterating over a list of names with List.iter to greet each one is like a captain going down the entire batting lineup individually to give each player specific instructions before the innings.

fsharp
// Program.fs
let greet name =
    sprintf "Hello, %s! Welcome to F#." name

[<EntryPoint>]
let main argv =
    let names = ["Alice"; "Bob"; "Priya"]
    names
    |> List.iter (fun n -> printfn "%s" (greet n))

    printfn "Program ran with %d argument(s)." argv.Length
    0   // exit code: 0 means success

A common beginner mistake is forgetting [<EntryPoint>] on main, or defining main above other functions it calls — remember, F# compiles top-to-bottom, so a function must be defined before anything that calls it, and main must appear last in the entry-point file.

printfn (with a trailing newline) and sprintf (which returns a formatted string instead of printing it) share the same %s/%d/%f-style format specifiers, and both are checked by the compiler — passing an int where %s expects a string is a compile error, not a runtime crash.

  • dotnet new console -lang "F#" -o HelloFSharp scaffolds a minimal project with a Program.fs file and a .fsproj.
  • F# compiles files top-to-bottom in the order listed in the .fsproj; a function must be defined before it's called.
  • [<EntryPoint>] marks the main function as the program's starting point; it must take string[] and return int.
  • printfn is F#'s type-safe formatted print function, using specifiers like %s, %d, and %f checked at compile time.
  • dotnet run builds and executes a full project; dotnet fsi script.fsx runs a script instantly without a project.
  • Returning 0 from main conventionally signals success; nonzero values signal an error to the calling shell.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#FStudyNotes#YourFirstFProgram#Program#Running#Dotnet#Run#StudyNotes#SkillVeris#ExamPrep