First, for newcomers and seasoned Godot users as well: I feel like wombatstampede's answer is not related to the OP's question, who was not asking about creating headless games/apps (no GUI in the final build, ie. background scripts), but rather about being able to code games/apps using GDScript without resorting to using Godot's editor for anything but rendering (and possibly coding inside the built-in code editor for ease of life).
Yes, it is possible to create a game/app using GDScript, without the editor needing to tie things up . Basically, one may attach a single "entrypoint" .gd script to the root scene's root node, and preload/import, instantiate and put to use everything programmatically from there:
extends Node # hi, I'm the root scene's root node
# I'm responsible for loading & using systems, entities, etc.
# Let's assume my beloved developer coded using OOP:
var main_state = preload("res://lib/systems/state.gd").new()
var player = preload("res://lib/actors/player.gd").new()
# Let's use all of these and create a decent game/app!
One may still use the editor to edit the .gd files, which comes in handy because it has good syntax highlighting, type checking, etc. But VSCode and its official extension is pretty good as well.
Now, is that a "good" practice? Your mileage may vary. I feel like using GDScript that way kind of goes against the flow. GDScript has been specifically designed for integrating with the editor, and somehow many features/syntax provided by & "exclusive" to GDScript benefit from tight coupling with the editor's UI (for instance, exported variables showing up in the inspector; tool scripts; etc.) One might be better off attaching not one but several/many .gd scripts to multiple, "key" nodes and keep the SOC to its usable minimum.
Please also remain aware that a somewhat "extreme" stance SRP-wise IMO would be to programmatically create most of your nodes (eg
var player = KinematicBody2D.new() etc. for most of the game entities/concepts), instead of creating an explicit node tree upfront using the editor. I feel like this is not the way Godot is meant to operate. Godot feels very strong when you create atomic, reusable scenes by aggregating child nodes/node types directly within the editor, so that anyone involved with project may then test and tweak things up (including non-programmers). The "glue (code)" might be programmatically handled for sure.
Related question/answers: here on game.stackexchange.